ExceptionTranslationFilter无法处理Spring Security异常,因为响应已提交

k5ifujac  于 2024-01-09  发布在  Spring
关注(0)|答案(1)|浏览(259)

我想在BasicAuthenticationFilter身份验证失败时抛出AuthenticationException,并统一处理,返回json。
但ExceptionTranslationFilter不起作用。
在ExceptionTranslationFilter.doFilter()中,它将检查response.isCommitted()并抛出“Unable to handle the Spring Security Exception because the response is already committed”。
所以这是正常的吗?我如何统一处理这些身份验证?
dependencies:spring-security:6.1.5.
SecurityFilterChain:

@Bean
public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
return httpSecurity
        .cors(AbstractHttpConfigurer::disable)
        .csrf(AbstractHttpConfigurer::disable)
        .sessionManagement(sessionManagement ->
                sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
        .addFilter(new JWTAuthenticationFilter(authenticationConfiguration.getAuthenticationManager(), objectMapper, whitelist))
        .addFilterAfter(new DecryptRequestFilter(), JWTAuthenticationFilter.class)
        .addFilterBefore(new ExceptionTranslationFilter(unauthorizedEntryPoint), JWTAuthenticationFilter.class)
        .build();
}

字符串
JWTAuthenticationFilter中的doFilterInternal()扩展了BasicAuthenticationFilter:

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
    String path = request.getRequestURI();
    AntPathMatcher antPathMatcher = new AntPathMatcher();
    if (whitelist.getWhitelist().stream().anyMatch(s -> antPathMatcher.match(s, path))) {
        chain.doFilter(request, response);
    }
    String token = request.getHeader(ConstantKey.HEADER_TOKEN_KEY);
    if(StringUtils.isEmpty(token)) {
        throw new AuthenticationCredentialsNotFoundException("token not found");
    }
    String subject = Jwts.parser().setSigningKey(ConstantKey.TOKEN_SIGN_KEY)
            .parseClaimsJws(token)
            .getBody()
            .getSubject();
    if (StringUtils.isEmpty(subject)) {
        throw new AuthenticationCredentialsNotFoundException("token is invalid");
    }
    AuthSubject authSubject;
    try {
        authSubject = objectMapper.readValue(subject, AuthSubject.class);
    }catch (Exception e) {
        throw new AuthenticationServiceException("read auth subject error", e);
    }
    Set<SimpleGrantedAuthority> simpleGrantedAuthorities = authSubject.getRoles().stream()
            .map(SimpleGrantedAuthority::new).collect(Collectors.toSet());
    UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
            new UsernamePasswordAuthenticationToken(authSubject.getUsername(), null, simpleGrantedAuthorities);
    SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
    request.setAttribute(AuthSubject.Fields.username, authSubject.getUsername());
    request.setAttribute(AuthSubject.Fields.roles, authSubject.getUserId());
    chain.doFilter(request, response);
}


UnauthorizedEntryPoint中的begin()实现AuthenticationEntryPoint:

@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
    response.setStatus(HttpStatus.UNAUTHORIZED.value());
    response.setContentType(ContentType.APPLICATION_JSON.toString());
    response.getWriter().write(objectMapper.writeValueAsString(
            GenericRestResponse.builder()
                    .status(YesOrNo.NO.getCode())
                    .message(authException.getMessage())
                    .build()
            )
    );
}


我尝试使用AuthenticationFailureException,但仍然无法捕获AuthenticationException。

piok6c0g

piok6c0g1#

我使用Spring Authorization Server来实现oauth2认证服务器。
参考youlai-mall项目实现密码认证方法。

相关问题