Spring Security 过滤器未触发

Spring Security filters not triggered

提问人:Hajji Achref 提问时间:7/12/2023 最后编辑:Hajji Achref 更新时间:7/13/2023 访问量:115

问:

我已经在我的spring java应用程序中实现了身份验证/授权机制。 这是我的配置类:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private CustomUserDetailsService userDetailsService;

    @Override
    public void configure(HttpSecurity http) throws Exception
    {
        http.csrf().disable()
                        .authorizeRequests()
                        .antMatchers("/login").permitAll()
                        .anyRequest().authenticated()
                        .and()
                        .addFilter(new JwtAuthenticationFilter(authenticationManager()))
                        .addFilterBefore(new JwtAuthorizationFilter(), UsernamePasswordAuthenticationFilter.class)
                        .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }

    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

}

这些是我的过滤器:

public class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

  private final AuthenticationManager authenticationManager;

  public JwtAuthenticationFilter(AuthenticationManager authenticationManager) {
    this.authenticationManager = authenticationManager;
  }

  @Override
  public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
    try {
      // Parse the user's credentials from the request body
      LoginRequest loginRequest = new ObjectMapper().readValue(request.getInputStream(), LoginRequest.class);

      System.out.println("loginRequest: " + loginRequest);

      // Create an authentication token with the user's credentials
      UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
              loginRequest.getUsername(),
              loginRequest.getPassword(),
              new ArrayList<>()
      );

      // Authenticate the user
      return authenticationManager.authenticate(authenticationToken);
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
  }

  @Override
  protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
    // Get the authenticated user's details
    BoUser userDetails = (BoUser) authResult.getPrincipal();

    // Create a JWT token for the user
    String token = JwtTokenUtil.generateToken(userDetails);

    // Add the token to the response headers
    response.addHeader("Authorization", "Bearer " + token);
  }
}
public class JwtAuthorizationFilter extends OncePerRequestFilter {

  @Override
  protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
    System.out.println("do filter internal");
    if (request.getMethod().equals("OPTIONS")) {
      response.setStatus(HttpServletResponse.SC_OK);
    }
    else {
      String jwtToken = request.getHeader(SecParams.JWT_HEADER_NAME);
      System.out.println("jwtToken = " + jwtToken);
      if (jwtToken == null || !jwtToken.startsWith(SecParams.HEADER_PREFIX)) {
        System.out.println("null or doesn't start with Bearer");
        filterChain.doFilter(request, response);
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        return;
      }
      JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(SecParams.SECRET)).build();
      System.out.println("jwtVerifier = " + jwtVerifier);
      DecodedJWT decodedJWT = jwtVerifier.verify(jwtToken.substring(SecParams.HEADER_PREFIX.length()));
      System.out.println("decodedJWT = " + decodedJWT);
      String email = decodedJWT.getSubject();
      System.out.println("email = " + email);
      List<String> roles = decodedJWT.getClaims().get("roles").asList(String.class);
      System.out.println("roles = " + roles);
      Collection<GrantedAuthority> authorities = new ArrayList<>();
      roles.forEach(rn -> {
        authorities.add(new SimpleGrantedAuthority(rn));
      });
      UsernamePasswordAuthenticationToken user = new UsernamePasswordAuthenticationToken(email, null, authorities);
      SecurityContextHolder.getContext().setAuthentication(user);
      filterChain.doFilter(request, response);
    }
  }
}

问题是这些过滤器在发送请求时不会触发;因此,我仍然可以访问资源,而无需在请求中发送令牌。

我想知道为什么我的过滤器没有被触发以及如何解决

Java Spring-安全 JWT

评论

0赞 J Asgarov 7/12/2023
你怎么知道它们没有被触发 - 你有没有尝试过使用调试器设置断点?日志显示什么?
0赞 Hajji Achref 7/12/2023
Usign System.out.println(),如上面的代码部分所示。没有打印任何内容,所以我知道它们没有被触发
0赞 Toerktumlare 7/12/2023
我希望你知道你所建造的东西是非常不安全的。使用 JWT 作为会话是非常不安全的,而且 spring 已经内置了对 JWT 的处理,所以与其关注糟糕的博客文章,不如阅读 spring 文档和 JWT 章节
0赞 Hajji Achref 7/12/2023
@Toerktumlare你能解释一下吗?
0赞 Toerktumlare 7/12/2023
如果你只是谷歌,你可以阅读所有关于它的信息。developer.okta.com/blog/2017/08/17/......我建议你先阅读什么是会话,然后阅读什么是JWT。JWT 是代币,它们并不意味着是一个会话,并且您正在暴露自己面临会话劫持和 XSS 的风险

答:

0赞 ownerofglory 7/13/2023 #1

对于与你提供的安全配置匹配的每个请求,都应调用你。JwtAuthorizationFilter

请记住,筛选器配置为按特定顺序运行。确保对单个请求最多执行一次特定过滤器。OncePerRequestFilter

但是,筛选器链的工作方式是,如果链中较早的筛选器已处理请求并且未调用 ,则链中的较晚筛选器将不会被调用。doFilterFilterChain

一个潜在的问题可能与你正在测试的网址模式有关。请记住,您允许所有请求无需身份验证。因此,如果您正在使用 进行测试,则不会调用 ,因为您允许所有请求/login/loginJwtAuthorizationFilter/login

此外,在 .但是,在 JWT 身份验证方案中,添加已定义的通常,用于代替JwtAuthorizationFilterUsernamePasswordAuthenticationFilterJwtAuthenticationFilterUsernamePasswordAuthenticationFilterJwtAuthenticationFilterUsernamePasswordAuthenticationFilter

评论

0赞 Hajji Achref 7/13/2023
我正在使用 url 来测试,但未调用该方法。我正在使用其他 url 来测试 .我尝试更改过滤器的顺序' .addFilterBefore(new JwtAuthenticationFilter(authenticationManager()), UsernamePasswordAuthenticationFilter.class) .addFilterBefore(new JwtAuthorizationFilter(), JwtAuthenticationFilter.class);',但这并不能解决问题/loginJwtAuthenticationFilterattemptAuthentication()JwtAuthorizationFilter