Spring Boot 2 - 基于过滤器的 JWT Spring Security 实现中的 403 而不是 401

作者:编程家 分类: spring 时间:2025-09-16

使用过滤器实现基于JWT的Spring Security时,我们可能会遇到403错误而不是预期的401错误。本文将介绍如何解决这个问题,并提供相关的案例代码。

在使用Spring Boot 2构建基于JWT的Spring Security时,我们通常会使用过滤器来验证和处理JWT。JWT(JSON Web Token)是一种用于身份验证和授权的安全传输方式。在Spring Security中,我们可以使用过滤器来拦截请求,并对JWT进行校验和解析。

然而,有时候我们可能会发现,当JWT无效或过期时,我们期望返回401错误(未授权),但实际上却返回了403错误(禁止访问)。这是因为Spring Security默认情况下,会对所有请求进行授权检查,包括那些未经身份验证的请求。

为了解决这个问题,我们需要对Spring Security的授权过滤器进行配置,以便在JWT无效或过期时返回401错误。

配置Spring Security

首先,我们需要创建一个自定义的过滤器,用于验证和解析JWT。这个过滤器需要继承自`OncePerRequestFilter`类,并重写`doFilterInternal`方法。

java

public class JwtAuthenticationFilter extends OncePerRequestFilter {

@Override

protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {

// 验证和解析JWT

// ...

filterChain.doFilter(request, response);

}

}

接下来,我们需要配置Spring Security,将这个自定义的过滤器添加到过滤器链中,并设置相应的授权策略。

java

@Configuration

@EnableWebSecurity

public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired

private JwtAuthenticationFilter jwtAuthenticationFilter;

@Override

protected void configure(HttpSecurity http) throws Exception {

http.csrf().disable()

.authorizeRequests()

.antMatchers("/api/public").permitAll()

.anyRequest().authenticated()

.and()

.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)

.exceptionHandling()

.authenticationEntryPoint((request, response, authenticationException) -> response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized"));

}

}

在上面的配置中,我们使用`jwtAuthenticationFilter`作为授权过滤器,并将其添加到`UsernamePasswordAuthenticationFilter`之前。同时,我们还设置了一个自定义的`authenticationEntryPoint`,用于处理未授权的请求,并返回401错误。

测试

现在,我们可以进行一些测试来验证我们的配置是否生效。假设我们有一个公开的API `/api/public`,不需要身份验证。而其它所有的API都需要进行身份验证。

当我们使用有效的JWT进行访问时,我们应该能够成功访问所有需要进行身份验证的API。

当我们使用无效或过期的JWT进行访问时,我们应该收到401错误(未授权)。

java

@RestController

public class ApiController {

@GetMapping("/api/public")

public ResponseEntity publicApi() {

return ResponseEntity.ok("Public API");

}

@GetMapping("/api/private")

public ResponseEntity privateApi() {

return ResponseEntity.ok("Private API");

}

}

在上面的代码中,`/api/public`是一个公开的API,不需要身份验证。而`/api/private`是一个私有的API,需要进行身份验证。

通过配置Spring Security的授权过滤器,我们可以解决基于过滤器的JWT Spring Security实现中返回403而不是401的问题。通过返回401错误,我们可以更准确地表示请求未经授权,而不是仅仅禁止访问。

通过本文的案例代码,我们可以清楚地了解到如何配置Spring Security和自定义过滤器来实现基于JWT的身份验证和授权。这将有助于我们构建更安全和可靠的应用程序。