您好,登录后才能下订单哦!
下面来通过一个实例讲解Session认证的方式
创建工程:
  
引入依赖:
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.0.4.RELEASE</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.8</version> </dependency> </dependencies> <build> <finalName>security‐springmvc</finalName> <pluginManagement> <plugins> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7‐maven‐plugin</artifactId> <version>2.2</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven‐compiler‐plugin</artifactId> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> <plugin> <artifactId>maven‐resources‐plugin</artifactId> <configuration> <encoding>utf‐8</encoding> <useDefaultDelimiters>true</useDefaultDelimiters> <resources> <resource> <directory>src/main/resources</directory> <filtering>true</filtering> <includes> <include>**/*</include> </includes> </resource> <resource> <directory>src/main/java</directory> <includes> <include>**/*.xml</include> </includes> </resource> </resources> </configuration> </plugin> </plugins> </pluginManagement> </build>
Spring容器配置
在config包下定义ApplicationConfig.java,这个配置类相当于spring的配置文件
@Configuration
@ComponentScan(basePackages = ,excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,value = Controller.)})ApplicationConfig {
    }在config包下定义WebConfig.java,这个配置类相当于springmv的配置文件
@Configuration @EnableWebMvc
@ComponentScan(basePackages = "cn.xh"
        ,includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,value = Controller.class)})public class WebConfig implements WebMvcConfigurer {
   
    //视频解析器
    @Bean
    public InternalResourceViewResolver viewResolver(){
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setPrefix("/WEB-INF/view/");
        viewResolver.setSuffix(".jsp");
        return viewResolver;
    }
}加载spring容器
在init包下定义spring容器的初始化类SpringApplicationInitializer,该类实现了WebApplicationInitializer接口相当于web.xml文件。Spring容器启动时会加载所有实现了WebApplicationInitializer接口的类。
public class SpringApplicationInitializer extends
        AbstractAnnotationConfigDispatcherServletInitializer {
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class<?>[] { ApplicationConfig.class };    } @
            Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class<?>[] { WebConfig.class };     } @
            Override
    protected String[] getServletMappings() {
        return new String [] {"/"};
    }
}该类对应的web.xml文件可以参考:
<web‐app>
<listener>
<listener‐class>org.springframework.web.context.ContextLoaderListener</listener‐class>
</listener>
<context‐param>
<param‐name>contextConfigLocation</param‐name>
<param‐value>/WEB‐INF/application‐context.xml</param‐value>
</context‐param>
<servlet>
<servlet‐name>springmvc</servlet‐name>
<servletclass>org.springframework.web.servlet.DispatcherServlet</servlet‐class>
<init‐param>
<param‐name>contextConfigLocation</param‐name>
<param‐value>/WEB‐INF/spring‐mvc.xml</param‐value>
</init‐param>
<load‐on‐startup>1</load‐on‐startup>
</servlet>
<servlet‐mapping>
<servlet‐name>springmvc</servlet‐name>
<url‐pattern>/</url‐pattern>
</servlet‐mapping>
</web‐app>
实现认证功能
在webapp/WEB-INF/views下定义认证页面login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
    <title>用户登录</title>
</head>
<body>
<form action="login" method="post">
    用户名:<input type="text" name="username"><br>
    密   码:
    <input type="password" name="password"><br>
    <input type="submit" value="登录">
</form>
</body>
</html>
在WebConfig中新增如下配置,将/直接导向login.jsp页面:
@Override
public void addViewControllers(ViewControllerRegistry registry) {
    registry.addViewController("/").setViewName("login");
}
启动项目,访问/路径地址,进行测试
创建认证接口;
认证接口用来对传入的用户名和密码进行验证,验证成功返回用户的详细信息,失败抛出错误异常。
public interface AuthenticationService {
    /**
     * 用户认证
     * @param authenticationRequest 用户认证请求
     * @return 认证成功的用户信息
     */
    UserDto authentication(AuthenticationRequest authenticationRequest);
}
认证请求结构:
@Data
public class AuthenticationRequest {
    /**
     * 用户名
     */
    private String username;
    /**
     * 密码
     */
    private String password;
}
用户详细信息:
@Data
@AllArgsConstructor
public class UserDto {
    private String id;
    private String username;
    private String password;
    private String fullname;
    private String mobile;
}
认证实现类:
@Service
public class AuthenticationServiceImpl implements AuthenticationService {
    @Override
    public UserDto authentication(AuthenticationRequest authenticationRequest) {
        if(authenticationRequest == null
                || StringUtils.isEmpty(authenticationRequest.getUsername())
                || StringUtils.isEmpty(authenticationRequest.getPassword())){
            throw new RuntimeException("账号或密码为空");
        }
        UserDto userDto = getUserDto(authenticationRequest.getUsername());
        if(userDto == null){
            throw new RuntimeException("查询不到该用户");
        }
        if(!authenticationRequest.getPassword().equals(userDto.getPassword())){
            throw new RuntimeException("账号或密码错误");
        }
        return userDto;
    }
    //模拟用户查询
    public UserDto getUserDto(String username){
        return userMap.get(username);
    }
    //用户信息
    private Map<String,UserDto> userMap = new HashMap<>();
    {
        userMap.put("zhangsan",new UserDto("1010","zhangsan","123","张三","133443"));
        userMap.put("lisi",new UserDto("1011","lisi","456","李四","144553"));
    }
}
登录controller:
@RestController
public class LoginController {
    @Autowired
    private AuthenticationService authenticationService;
    /**
     * 用户登录
     * @param authenticationRequest 登录请求
     * @return
     */
    @PostMapping(value = "/login",produces = "text/plain;charset=utf‐8")   
public String login(AuthenticationRequest authenticationRequest){
        UserDto userDto = authenticationService.authentication(authenticationRequest);
        return userDto.getFullname() + " 登录成功";
    }
}
测试
实现会话功能:
当用户登录系统后,系统需要记住用户的信息,一般会把用户的信息放在session中,在需要的时候从session中获取用户的信息,这就是会话机制。
首先在UserDto中定义一个Session_USER_KEY,作为session的key
public static final String SESSION_USER_KEY = "_user";
修改LoginController,认证成功后,将用户的信息放入session,并增加用户注销的方法,用户注销时清空session
@PostMapping(value = "/login",produces = "text/plain;charset=utf‐8")
    public String login(AuthenticationRequest authenticationRequest, HttpSession session){
        UserDto userDto = authenticationService.authentication(authenticationRequest);
//用户信息存入session
        session.setAttribute(UserDto.SESSION_USER_KEY,userDto);
        return userDto.getUsername() + "登录成功";
    }
    @GetMapping(value = "logout",produces = "text/plain;charset=utf‐8")
    public String logout(HttpSession session){
        session.invalidate();
        return "退出成功";
    }
增加测试资源,在LoginController中增加测试资源:
@GetMapping(value = "/r/r1",produces = {"text/plain;charset=utf-8"})
public String r1(HttpSession session){
    String fullname = null;
    Object userObj = session.getAttribute(UserDto.SESSION_USER_KEY);
    if(userObj != null){
        fullname = ((UserDto)userObj).getFullname();
    }else{
        fullname = "匿名";
    }
    return fullname + " 访问资源1";
}
测试:
未登录访问 /r/r1显示:
已登录访问 /r/r1显示:
实现授权功能
用户访问系统需要经过授权,需要完成如下功能:
禁止未登录用户访问某些资源
登录用户根据用户的权限决定是否能访问某些资源
第一步:在UserDto里增加权限属性表示该登录用户拥有的权限:
@Data
@AllArgsConstructor
public class UserDto {
    public static final String SESSION_USER_KEY = "_user";
    private String id;
    private String username;
    private String password;
    private String fullname;
    private String mobile;
    /**
     * 用户权限
     */
    private Set<String> authorities;
}
第二步:在AuthenticationServiceImpl中为用户初始化权限,张三给了p1权限,李四给了p2权限:
//用户信息
private Map<String,UserDto> userMap = new HashMap<>();
{
    Set<String> authorities1 = new HashSet<>();
    authorities1.add("p1");
    Set<String> authorities2 = new HashSet<>();
    authorities2.add("p2");
    userMap.put("zhangsan",new UserDto("1010","zhangsan","123","张三","133443",authorities1));
            userMap.put("lisi",new UserDto("1011","lisi","456","李四","144553",authorities2));
}
第三步:在LoginController中增加测试资源:
/**
 * 测试资源2
 * @param session
 * @return
 */
@GetMapping(value = "/r/r2",produces = {"text/plain;charset=utf-8"})
public String r2(HttpSession session){
    String fullname = null;
    Object userObj = session.getAttribute(UserDto.SESSION_USER_KEY);
    if(userObj != null){
        fullname = ((UserDto)userObj).getFullname();
    }else{
        fullname = "匿名";
    }
    return fullname + " 访问资源2";
}
第四步:在interceptor包下实现授权拦截器SimpleAuthenticationInterceptor:
校验用户是否登录
校验用户是否有操作权限
@Component
public class SimpleAuthenticationInterceptor implements HandlerInterceptor {
    //请求拦截方法
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object
            handler) throws Exception {
//读取会话信息
        Object object = request.getSession().getAttribute(UserDto.SESSION_USER_KEY);
        if (object == null) {
            writeContent(response, "请登录");
        }
        UserDto user = (UserDto) object;
//请求的url
        String requestURI = request.getRequestURI();
        if (user.getAuthorities().contains("p1") && requestURI.contains("/r1")) {
            return true;
        }
        if (user.getAuthorities().contains("p2") && requestURI.contains("/r2")) {
            return true;
        }
        writeContent(response, "权限不足,拒绝访问");
        return false;
    }
    //响应输出
    private void writeContent(HttpServletResponse response, String msg) throws IOException {
        response.setContentType("text/html;charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.print(msg);
        writer.close();
        response.resetBuffer();
    }
}
在WebConfig中配置拦截器,配置/r/**的资源被拦截器处理:
@Autowired
private SimpleAuthenticationInterceptor simpleAuthenticationInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(simpleAuthenticationInterceptor).addPathPatterns("/r/**");
}
测试:
未登录:
张三访问/r/r1:
张三访问 /r/r2:
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。