github源码:
https://github.com/gyb123456/spring-security5-jwt,最烦那些写文档只截图一半还不给源码的人,要不你就截全图,要不就给源码!
前言:
需要研究spring-security和jwt技术,搞了几天,现把成果记录下
环境
Springboot:2.1.3.RELEASE
spring-security:5.1.4.RELEASE
前后端分离
所需依赖3个,具体pom见源码
org.springframework.boot spring-boot-starter-security io.jsonwebtoken jjwt 0.9.0org.projectlombok lombok true
spring-security原理
从网上的各种不同方法综合一下形成了这一套完整框架,源码里每个类各司其职,很清晰知道是干什么的,现在讲一下spring-security原理及工作流程
图片中各个类的作用:
1 JwtUser类:实现Springsecurity的UserDetails类,此类必须有三个属性
private String username;
private String password;
//权限,类如ROLE_ADMIN
private Collection extends GrantedAuthority> authorities;
2 JwtUtils:jwt工具类
3 MD5Util:密码加密工具类
4 MyAccessDeniedHandler:实现Springsecurity的AccessDeniedHandler,Spring security权限不足处理类
5 MyAuthenticationException:实现Springsecurity的AuthenticationEntryPoint,Spring security其他异常处理类,比如请求路径不存在等
6 MyAuthenticationFailHandler: 实现Springsecurity的AuthenticationFailureHandler,Spring security登录失败处理类
7 MyAuthenticationSuccessHandler:实现Springsecurity的AuthenticationSuccessHandler,Spring security登录成功处理类
8 MyJwtTokenFilter: 继承Springsecurity的OncePerRequestFilter,token 过滤器,在这里解析token,拿到该用户角色,设置到springsecurity的上下文环境中,让springsecurity自动判断权限
9 MyUserDetailsService:实现Springsecurity的UserDetailsService,根据用户名获取数据库该用户信息,spring security在登录时自动调用
10 WebSecurityConfig: Spring security的总配置类,配置密码验证规则、拦截的url、登录接口地址、登录成功与失败后的处理器、各种异常处理器
总结:
spring-security工作流程就是
1自动识别登录接口路径(你配置的),自动进入账户密码判断方法,判断规则可自定义,密码验证通过后会进入spring security提供的MyAuthenticationSuccessHandler类,在这里重写方法,用HttpServletResponse自定义返回给前端内容,可以返回接口也可以返回html,随你,我这里返回jwt。验证失败同理。
这里说下 Spring security的账户密码判断逻辑,WebSecurityConfig继承WebSecurityConfigurerAdapter,注入configureAuthentication方法,重写matches方法自定义密码验证规则,返回boolean
@Autowired public void configureAuthentication(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception { authenticationManagerBuilder // 设置UserDetailsService 获取user对象 .userDetailsService(this.userDetailsService) // 自定义密码验证方法 .passwordEncoder(new PasswordEncoder() { //这个方法没用 @Override public String encode(CharSequence charSequence) { return ""; } //自定义密码验证方法,charSequence:用户输入的密码,s:我们查出来的数据库密码 @Override public boolean matches(CharSequence charSequence, String s) { String pass = MD5Util.string2MD5(charSequence.toString()); System.out.println("用户输入密码:" + charSequence + "与数据库相同?" + s.equals(pass)); return s.equals(pass); } }); }
2登录成功后,前端携带jwt的token来访问接口,首先会进入我们配置的MyJwtTokenFilter 类继承自OncePerRequestFilter,这个OncePerRequestFilter就厉害了,可以说是所有filter的基类,所以最先执行,在这里我们写验证jwt的逻辑,验证通过后要告诉springsecurity,我们获取到的用户的权限,并把权限设置到springsecurity的上下文环境中,让它来给我们做权限的判断,这点最重要!!!!是springsecurity和jwt的整合纽带,主要代码如下:
if(JwtUtils.isTokenExpired(Claims)){//token过期 System.out.println("token过期" + authToken); }else{ System.out.println("token没过期,放行" + authToken); UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(UserDetails, null, UserDetails.getAuthorities()); authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpServletRequest)); logger.info(String.format("Authenticated userDetail %s, setting security context