前后端分离与分布式环境下,session不好使了,这时要着重使用令牌了
这时利用框架提供的两个父类
UsernamePasswordAuthenticationFilter 用于登录验证
BasicAuthenticationFilter 用于令牌验证

登录验证过滤器 UsernamePasswordAuthenticationFilter

  1. /**
  2. * 认证过滤器
  3. *
  4. * @author YUDI
  5. * @date 2020/4/10
  6. */
  7. public class LoginFilter extends UsernamePasswordAuthenticationFilter {
  8. private AuthenticationManager authenticationManager;
  9. private RsaKeyProperties prop;
  10. public LoginFilter(AuthenticationManager authenticationManager, RsaKeyProperties prop) {
  11. this.authenticationManager = authenticationManager;
  12. this.prop = prop;
  13. // /login为内置接口
  14. this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/login", "POST"));
  15. }
  16. /**
  17. * 处理登录请求的方法
  18. *
  19. * @param request
  20. * @param response
  21. * @return
  22. * @throws AuthenticationException
  23. */
  24. @Override
  25. public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
  26. try {
  27. //将前端传入的参数转换成实体类对象
  28. User user = new ObjectMapper().readValue(request.getInputStream(), User.class);
  29. //账号密码登录 将访问UserDetailsService的方法
  30. UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword());
  31. //认证通过
  32. return authenticationManager.authenticate(authRequest);
  33. } catch (Exception e) {
  34. try {
  35. response.setContentType("application/json;charset=utf-8");
  36. //没有认证的编码
  37. response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
  38. PrintWriter out = response.getWriter();
  39. Map<String, Object> resultMap = new HashMap<>(2);
  40. resultMap.put("code", HttpServletResponse.SC_UNAUTHORIZED);
  41. resultMap.put("msg", "用户名或密码错误");
  42. out.write(new ObjectMapper().writeValueAsString(resultMap));
  43. out.flush();
  44. out.close();
  45. } catch (Exception outEx) {
  46. throw new RuntimeException(outEx);
  47. }
  48. throw new RuntimeException(e);
  49. }
  50. }
  51. /**
  52. * 认证成功之后执行的方法(在响应头里颁发令牌)
  53. *
  54. * @param request
  55. * @param response
  56. * @param chain
  57. * @param authResult
  58. * @throws IOException
  59. * @throws ServletException
  60. */
  61. @Override
  62. public void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
  63. User user = new User();
  64. user.setUsername(authResult.getName());
  65. //设置权限
  66. user.setPermissions((List<Permission>) authResult.getAuthorities());
  67. //设置令牌有效期 时间单位为分钟
  68. String token = JwtUtils.generateTokenExpireInMinutes(user, prop.getPrivateKey(), 24 * 60);
  69. response.addHeader("Authorization", "Bearer " + token);
  70. try {
  71. response.setContentType("application/json;charset=utf-8");
  72. //没有认证的编码
  73. response.setStatus(HttpServletResponse.SC_OK);
  74. PrintWriter out = response.getWriter();
  75. Map<String, Object> resultMap = new HashMap<>();
  76. resultMap.put("code", HttpServletResponse.SC_OK);
  77. resultMap.put("msg", "认证通过");
  78. out.write(new ObjectMapper().writeValueAsString(resultMap));
  79. out.flush();
  80. out.close();
  81. } catch (Exception outEx) {
  82. outEx.printStackTrace();
  83. }
  84. }
  85. }

令牌过滤器 BasicAuthenticationFilter

/**
 * 验证认证过滤器
 *
 * @author YUDI
 * @date 2020/4/10
 */
public class JwtVerifyFilter extends BasicAuthenticationFilter {

    private RsaKeyProperties prop;

    public JwtVerifyFilter(AuthenticationManager authenticationManager, RsaKeyProperties prop) {
        super(authenticationManager);
        this.prop = prop;
    }

    @Override
    public void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        String header = request.getHeader("Authorization");
        if (header == null || !header.startsWith("Bearer ")) {
            //如果携带错误格式的token,则给用户提示请登录!
            response.setContentType("application/json;charset=utf-8");
            response.setStatus(HttpServletResponse.SC_FORBIDDEN);
            PrintWriter out = response.getWriter();
            Map<String, Object> resultMap = new HashMap<>();
            resultMap.put("code", HttpServletResponse.SC_FORBIDDEN);
            resultMap.put("msg", "没有登录或权限不够");
            out.write(new ObjectMapper().writeValueAsString(resultMap));
            out.flush();
            out.close();
            chain.doFilter(request, response);
        } else {
            //如果携带了正确格式的token要先得到token
            String token = header.replace("Bearer ", "");
            //验证token是否正确
            Payload<User> payload = JwtUtils.getInfoFromToken(token, prop.getPublicKey(), User.class);
            //根据令牌得到用户信息
            User user = payload.getUserInfo();
            if (user != null) {
                UsernamePasswordAuthenticationToken authResult = new UsernamePasswordAuthenticationToken(user.getUsername(), token, user.getAuthorities());
                //授权
                SecurityContextHolder.getContext().setAuthentication(authResult);
                chain.doFilter(request, response);
            } else {
                response.setContentType("application/json;charset=utf-8");
                PrintWriter out = response.getWriter();
                Map<String, Object> resultMap = new HashMap<>();
                resultMap.put("msg", "token有误");
                out.write(new ObjectMapper().writeValueAsString(resultMap));
                out.flush();
                out.close();
                chain.doFilter(request, response);
            }

        }

    }


}

security配置类

在这个配置类里 配置前面两个过滤器,如果作为资源服务则只需要配置令牌过滤器即可

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private MyUserDetailsServiceImpl userDetailsService;

    @Autowired
    private RsaKeyProperties prop;

    //配置BCrypt加密方案
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    //配置用户信息和权限
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //使用数据库动态添加
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }

    @Override
    //配置拦截请求资源
    protected void configure(HttpSecurity http) throws Exception {
        http.headers().frameOptions().disable();
        //关闭打开的csrf保护
        http.csrf().disable();

        //如何权限控制 给每一条路径分配一个权限名称 账号只要管理该名称 就可以访问权限

        //url含有order的需要认证才能访问 fullyAuthenticated方法
        http.authorizeRequests()
                .antMatchers("/order/**").fullyAuthenticated()
                .and()
                //配置过滤器
                .addFilter(new LoginFilter(super.authenticationManager(), prop))
                .addFilter(new JwtVerifyFilter(super.authenticationManager(), prop))
                //禁用session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

    }

}