使用有效JWT调用SpringBoot接口时为何返回401未授权?
问题排查与解决方案
针对你遇到的JWT认证通过但接口返回401的问题,结合日志中"SecurityContext被清空、跳转/error页面匿名访问被拒"的线索,可按以下步骤排查解决:
1. 优先处理错误页面权限拦截
日志显示最终401是因为跳转至/error页面时匿名访问被拒绝,先开放该端点的访问权限:
@Bean public SecurityFilterChain getSecurityFilterChain(HttpSecurity http) throws Exception { http.authorizeRequests(authz -> authz .antMatchers(HttpMethod.GET, "/companies").hasAuthority("SCOPE_profile") .antMatchers("/error").permitAll() // 允许所有用户访问错误页面 .anyRequest().authenticated()) .oauth2ResourceServer(oauth2 -> oauth2.jwt()); return http.build(); }
2. 验证JWT令牌的权限匹配
确认你的JWT令牌中包含profile scope:
- 用jwt.io解析令牌,检查
scope或scp字段是否存在profile值 - Spring Security会自动将JWT中的scope转换为
SCOPE_xxx格式的权限,若令牌无此scope,需在Keycloak客户端配置中添加对应权限,或在获取令牌时指定scope=profile
3. 修正控制器参数解析问题
控制器方法中的JwtAuthenticationToken principal参数可能导致Spring MVC解析异常,进而触发错误跳转,建议替换为更稳妥的写法:
@GetMapping CollectionModel<CompanyResponseDTO> getCompanies(@AuthenticationPrincipal Jwt jwt);
或直接获取Authentication对象:
@GetMapping CollectionModel<CompanyResponseDTO> getCompanies(Authentication authentication);
4. 优化路径匹配准确性
将antMatchers替换为mvcMatchers,它会自动适配Spring MVC的context-path和@RequestMapping规则,避免路径匹配错误:
.mvcMatchers(HttpMethod.GET, "/companies").hasAuthority("SCOPE_profile")
5. 确保无状态SecurityContext配置
对于REST服务,建议明确配置无状态的SecurityContext存储,避免Session相关的上下文清空问题:
@Bean public SecurityFilterChain getSecurityFilterChain(HttpSecurity http) throws Exception { http.authorizeRequests(authz -> authz .mvcMatchers(HttpMethod.GET, "/companies").hasAuthority("SCOPE_profile") .antMatchers("/error").permitAll() .anyRequest().authenticated()) .oauth2ResourceServer(oauth2 -> oauth2.jwt()) .securityContext(context -> context .securityContextRepository(new NullSecurityContextRepository()) // 禁用Session存储 ); return http.build(); }
6. 验证Keycloak配置有效性
检查application.yml中的issuer-uri是否可访问,Spring Boot需要通过该地址获取JWKS公钥来验证JWT。查看日志中是否有类似"Loaded JWKS from ..."的信息,确认公钥加载正常。
内容的提问来源于stack exchange,提问作者Shurbann Martes
相关产品推荐
相关产品推荐

