在Dispatcher Servlet Spring Security中处理请求之前出现错误403(Forbidden)

a64a0gku  于 5个月前  发布在  Spring
关注(0)|答案(1)|浏览(35)

此问题在此处已有答案

Spring Boot 3 with Spring Security Intercepts exceptions I don't want it to(2个答案)
23天前关闭
我在使用Spring Security的应用程序中遇到了问题。如果出现任何错误,在请求到达Dispatcher Servlet之前,返回错误状态403(禁止)。
问题甚至在请求到达Dispatcher Servlet之前就发生了。例如,当我尝试访问/API/v1/offer路径时,我验证字段,发生错误,之后Spring security发送403响应。即使我写了一个不存在的URL而不是404响应(未找到),我也会得到403响应。
如果您能在通过Dispatcher Servlet传递请求之前就如何解决此问题提供任何建议或提示,我将不胜感激。
下面是我的Spring Security配置:

@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
@EnableMethodSecurity
public class SecurityConfiguration {

private final AuthenticationProvider authenticationProvider;
private final LogoutHandler logoutHandler;

@Value("${adapter.controller.base-path}")
private String basePath;

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http, UserDetailsService userDetailsService, JwtService jwtService) throws Exception {
    http
            .csrf()
            .disable()
            .cors()
            .and()
            .authorizeHttpRequests(
                    c -> c
                            .requestMatchers("/api/v1/employee/**").hasAnyRole(ADMIN.name(), USER.name(), HR.name())
                            .requestMatchers(GET, basePath + "/employee/**").hasAnyAuthority(ADMIN_READ.name(), USER_READ.name())
                            .requestMatchers(POST, basePath + "/employee/**").hasAnyAuthority(ADMIN_CREATE.name(), USER_CREATE.name())
                            .requestMatchers(PUT, basePath + "/employee/**").hasAnyAuthority(ADMIN_UPDATE.name(), USER_UPDATE.name())
                            .requestMatchers(DELETE, basePath + "/employee/**").hasAnyAuthority(ADMIN_DELETE.name(), USER_DELETE.name())
                            .anyRequest()
                            .authenticated())
            .sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
            .authenticationProvider(authenticationProvider)
            .addFilterBefore(new JwtAuthenticationFilter(userDetailsService, jwtService), UsernamePasswordAuthenticationFilter.class)
            .logout()
            .logoutUrl(basePath + "/auth/logout")
            .addLogoutHandler(logoutHandler)
            .logoutSuccessHandler((request, response, authentication) -> SecurityContextHolder.clearContext());

    return http.build();
}

@Bean
public WebSecurityCustomizer ignoringCustomizer() {
    return (web) -> web.ignoring().requestMatchers(basePath + "/auth", "/swagger-ui/**", "/v3/api-docs/**");
}
}

字符串
下面是我的自定义过滤器:

@Slf4j
@RequiredArgsConstructor
public class JwtAuthenticationFilter extends OncePerRequestFilter {
public static final String BEARER_SUBSTRING = "Bearer ";
private final UserDetailsService userDetailsService;
private final JwtService jwtService;
private final AuthenticationEntryPoint entryPoint = new BearerTokenAuthenticationEntryPoint();

@Override
protected void doFilterInternal(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull FilterChain filterChain) throws ServletException, IOException {
    final String authHeader = request.getHeader(HttpHeaders.AUTHORIZATION);
    final String jwt;
    final String userEmail;
    if (authHeader == null || !authHeader.startsWith(BEARER_SUBSTRING)) {
        log.error("Authentication headers not found.");
        entryPoint.commence(request, response, new AuthenticationCredentialsNotFoundException("Authentication headers not found."));
        return;
    }
    jwt = authHeader.substring(BEARER_SUBSTRING.length());
    try {
        userEmail = jwtService.extractEmail(jwt);
        if (userEmail != null && SecurityContextHolder.getContext().getAuthentication() == null) {
            UserDetails userDetails = this.userDetailsService.loadUserByUsername(userEmail);
            if (jwtService.isTokenValid(jwt, userDetails)) {
                UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                SecurityContextHolder.getContext().setAuthentication(authToken);
            }
        }
        filterChain.doFilter(request, response);
    } catch (ExpiredJwtException e) {
        log.error(e.getMessage());
        entryPoint.commence(request, response, new CredentialsExpiredException(e.getMessage()));
    }
}
}

7fhtutme

7fhtutme1#

允许任何人访问错误端点:

@Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http, UserDetailsService userDetailsService, JwtService jwtService) throws Exception {
    http
            .csrf()
            .disable()
            .cors()
            .and()
            .authorizeHttpRequests(
                    c -> c
                            .requestMatchers("error").permitAll()
                            .requestMatchers("/api/v1/employee/**").hasAnyRole(ADMIN.name(), USER.name(), HR.name())
                            .requestMatchers(GET, basePath + "/employee/**").hasAnyAuthority(ADMIN_READ.name(), USER_READ.name())
                            .requestMatchers(POST, basePath + "/employee/**").hasAnyAuthority(ADMIN_CREATE.name(), USER_CREATE.name())
                            .requestMatchers(PUT, basePath + "/employee/**").hasAnyAuthority(ADMIN_UPDATE.name(), USER_UPDATE.name())
                            .requestMatchers(DELETE, basePath + "/employee/**").hasAnyAuthority(ADMIN_DELETE.name(), USER_DELETE.name())
                            .anyRequest()
                            .authenticated())
            .sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
            .authenticationProvider(authenticationProvider)
            .addFilterBefore(new JwtAuthenticationFilter(userDetailsService, jwtService), UsernamePasswordAuthenticationFilter.class)
            .logout()
            .logoutUrl(basePath + "/auth/logout")
            .addLogoutHandler(logoutHandler)
            .logoutSuccessHandler((request, response, authentication) -> SecurityContextHolder.clearContext());

    return http.build();
}

字符串
问题是,当错误发生时,Spring会将用户发送到/error端点,但在您的情况下,该端点是受保护的,因此当用户试图访问它时,它会被拒绝,用户会得到403。

相关问题