尝试访问资源时出现 Spring security jwt token 403 错误
Posted
技术标签:
【中文标题】尝试访问资源时出现 Spring security jwt token 403 错误【英文标题】:Spring security jwt token 403 error when trying to access a resource 【发布时间】:2021-10-12 13:46:02 【问题描述】:JwtRequestFilter:
package com.rest.app.filters;
import com.rest.app.services.MyUserDetailsService;
import com.rest.app.util.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class JwtRequestFilter extends OncePerRequestFilter
@Autowired
private MyUserDetailsService userDetailsService;
@Autowired
private JwtUtil jwtUtil;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException
final String authorizationHeader = request.getHeader("Authorization");
System.out.println(authorizationHeader);
String userName = null;
String jwt = null;
if (authorizationHeader != null && authorizationHeader.startsWith("Bearer "))
jwt = authorizationHeader.substring(7);
userName = jwtUtil.extractUserName(jwt);
if (userName != null && SecurityContextHolder.getContext().getAuthentication() != null)
UserDetails userDetails = userDetailsService.loadUserByUsername(userName);
if (jwtUtil.validateToken(jwt, userDetails))
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
usernamePasswordAuthenticationToken
.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
filterChain.doFilter(request, response);
应用:
package com.rest.app;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@SpringBootApplication
public class RestApplication
public static void main(String[] args)
SpringApplication.run(RestApplication.class, args);
@Bean
public WebMvcConfigurer corsConfigurer()
return new WebMvcConfigurer()
@Override
public void addCorsMappings(CorsRegistry registry)
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "PUT", "POST", "PATCH", "DELETE", "OPTIONS")
.allowedHeaders("*");
;
安全配置器:
package com.rest.app.configuration;
import com.rest.app.filters.JwtRequestFilter;
import com.rest.app.services.MyUserDetailsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@EnableWebSecurity
public class SecurityConfigurer extends WebSecurityConfigurerAdapter
@Autowired
private MyUserDetailsService myUserDetailsService;
@Autowired
private JwtRequestFilter jwtRequestFilter;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
auth.userDetailsService(myUserDetailsService);
@Override
protected void configure(HttpSecurity http) throws Exception
http.cors().and().csrf().disable()
.authorizeRequests().antMatchers("/authenticate", "/user/create", "/user/login").permitAll()
.anyRequest().authenticated()
.and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
@Bean
public PasswordEncoder passwordEncoder()
return NoOpPasswordEncoder.getInstance();
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception
return super.authenticationManagerBean();
我仍然得到这个:
"timestamp":"2021-08-08T15:23:52.656+00:00","status":403,"error":"Forbidden","path":"/api/user/account/deposit"
响应标头:
Vary: origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Access-Control-Allow-Origin: *
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Type: application/json
Transfer-Encoding: chunked
Date: Sun, 08 Aug 2021 15:37:25 GMT
Keep-Alive: timeout=60
Connection: keep-alive
请求标头:
Access-Control-Allow-Origin: *
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Connection: keep-alive
Content-Type: application/json
Date: Sun, 08 Aug 2021 15:23:52 GMT
Expires: 0
Keep-Alive: timeout=60
Pragma: no-cache
Transfer-Encoding: chunked
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate, br
Accept-Language: pl-PL,pl;q=0.9,en-US;q=0.8,en;q=0.7
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJtYXJlazEyMyIsImV4cCI6MTYyODQ3MjE5MiwiaWF0IjoxNjI4NDM2MTkyfQ.rxUQ3uzCTtriMUkrKCayBDCQ4Q4aXTHD_z-R7A8Oduc
Connection: keep-alive
Content-Length: 2
Content-Type: application/json;charset=UTF-8
Host: localhost:8080
Origin: http://localhost:3000
Referer: http://localhost:3000/
sec-ch-ua: "Opera";v="77", "Chromium";v="91", ";Not A Brand";v="99"
sec-ch-ua-mobile: ?0
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (Khtml, like Gecko) Chrome/91.0.4472.164 Safari/537.36 OPR/77.0.4054.277
即使我在授权请求标头中发送 jwt 令牌,我也无法获取此资源。 OPTIONS 请求通过,状态码 200 没有问题。是关于我的 jwt 授权还是我的 CORS 配置?我正在使用弹簧安全。我已经尝试了所有我能找到的解决方案。
【问题讨论】:
你的调试日志在说什么? 另外编写自定义 jwt 过滤器是不好的做法,spring security 已经完全支持 jwt 3 年了,请阅读 spring security 参考文档中的章节。 【参考方案1】:我在我的 JwtRequestFilter 中找到了原因,而不是这个:
SecurityContextHolder.getContext().getAuthentication() != null
应该是这样的:
SecurityContextHolder.getContext().getAuthentication() == null
【讨论】:
以上是关于尝试访问资源时出现 Spring security jwt token 403 错误的主要内容,如果未能解决你的问题,请参考以下文章
Spring Security 4. 指定访问决策管理器时出现异常
Spring Security 4. 指定访问决策管理器时出现异常
Spring Security 4. 指定访问决策管理器时出现异常