目录

Spring Security + JWT

目录

/images/web/spring-security-architecture.png

/images/web/AuthCodeFlowSequenceDiagram-1.png

spring-boot-starter-oauth2-resource-server

spring-boot-starter-oauth2-client

https://www.baeldung.com/spring-security-oauth-resource-server

默认的 UsernamePasswordAuthenticationFilter过滤器通过 from 表单 post 请求形式获取用户名username密码password参数

请求头为 application/x-www-form-urlencoded

鉴于官方已有 UsernamePasswordAuthenticationFilter过滤器,所以我们可以直接复制一个过来修改一下即可

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
LoginRequest loginRequest = null;
      String username;
      try (InputStream io = request.getInputStream()) {
        loginRequest = objectMapper.readValue(io, LoginRequest.class);
        username = UserUtil.getUsername(loginRequest);
        if (StringUtils.isBlank(username)) {
          throw new BaseAuthenticationException(ResponseEnum.EMPTY_PARAMETER_ERROR);
        }
      } catch (IOException e) {
        // 登录没有输入参数
        throw new BaseAuthenticationException(ResponseEnum.EMPTY_PARAMETER_ERROR);
      }

@Bean
UsernamePasswordJsonAuthenticationFilter usernamePasswordJsonAuthenticationFilter() {
    UsernamePasswordJsonAuthenticationFilter filter = new UsernamePasswordJsonAuthenticationFilter();
    // 登录成功处理
    filter.setAuthenticationSuccessHandler(myAuthenticationSuccessHandler);
    // 登录失败处理器
    filter.setAuthenticationFailureHandler(myAuthenticationFailureHandler);
    reuturn filter;
}

http.addFilterAt(usernamePasswordJsonAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);

仿照 BasicAuthenticationFilter 写 JwtTokenAuthenticationFilter

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
@Component
public class JwtTokenAuthenticationFilter extends OncePerRequestFilter {

    private final JwtTokenUtil jwtTokenUtil;
    private final UserRepo userRepo;

    public JwtTokenFilter(JwtTokenUtil jwtTokenUtil,
                          UserRepo userRepo) {
        this.jwtTokenUtil = jwtTokenUtil;
        this.userRepo = userRepo;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain chain)
            throws ServletException, IOException {
        // Get authorization header and validate
        final String header = request.getHeader(HttpHeaders.AUTHORIZATION);
        if (isEmpty(header) || !header.startsWith("Bearer ")) {
            chain.doFilter(request, response);
            return;
        }

        // Get jwt token and validate
        final String token = header.split(" ")[1].trim();
        if (!jwtTokenUtil.validate(token)) {
            chain.doFilter(request, response);
            return;
        }

        // Get user identity and set it on the spring security context
        UserDetails userDetails = userRepo
            .findByUsername(jwtTokenUtil.getUsername(token))
            .orElse(null);

        UsernamePasswordAuthenticationToken
            authentication = new UsernamePasswordAuthenticationToken(
                userDetails, null,
                userDetails == null ?
                    List.of() : userDetails.getAuthorities()
            );

        authentication.setDetails(
            new WebAuthenticationDetailsSource().buildDetails(request)
        );

        SecurityContextHolder.getContext().setAuthentication(authentication);
        chain.doFilter(request, response);
    }

}