Spring/Boot - JWT 未在 GET 请求中获取
Posted
技术标签:
【中文标题】Spring/Boot - JWT 未在 GET 请求中获取【英文标题】:Spring/Boot - JWT not being picked up on GET request 【发布时间】:2020-12-09 16:24:19 【问题描述】:我有一个 Spring/Boot REST API,它为会话提供 JWT 令牌。
我有一个带有 2 种方法的会话端点,一种用于验证用户身份,一种用于验证 Auth Token。我可以在端点上成功创建和验证令牌(这些令牌上没有过滤器)。一旦我尝试使用客户端应用程序访问端点,请求就会爆炸,但是我可以在 REST 客户端(如 insomnia)中正常使用它们。
通过 JWT 令牌运行的代码在这里:
@Component
public class JwtRequestFilter extends OncePerRequestFilter
private final UserService userService;
private final JwtTokenUtility jwtTokenUtility;
@Autowired
public JwtRequestFilter(
UserService userService,
JwtTokenUtility jwtTokenUtility
)
this.userService = userService;
this.jwtTokenUtility = jwtTokenUtility;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException
final String requestTokenHeader = request.getHeader("Authorization"); <-- null
String username = null;
String jwtToken = null;
if (requestTokenHeader != null && requestTokenHeader.startsWith("Bearer "))
jwtToken = requestTokenHeader.substring(7);
try
username = jwtTokenUtility.getUsernameFromToken(jwtToken);
catch (IllegalArgumentException e)
System.out.println("Unable to get JWT Token");
catch (ExpiredJwtException e)
System.out.println("JWT Token has expired");
else
logger.warn("JWT Token does not begin with Bearer String"); <-- Therefore, this is called
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null)
UserDetails userDetails = this.userService.loadUserByUsername(username);
if (jwtTokenUtility.validateToken(jwtToken, userDetails))
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
usernamePasswordAuthenticationToken
.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
filterChain.doFilter(request, response);
问题是代码读取授权请求头为空,但是当我检查请求头时,它显然在那里:
Provisional headers are shown
Accept: application/json, text/plain, */*
Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJkdWRlY29yMyIsImV4cCI6MTU5NzkzNTQ0NywiaWF0IjoxNTk3OTE3NDQ3fQ.phMnbmkvOW6HKLCnWso-GaX844KMkukS5eADMBko56EEJA-VGgG1qpavwPwHT-tKjxbMuO9VZw3T0rESxQpIqQ
Referer: http://localhost:4200/
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (Khtml, like Gecko) Chrome/84.0.4147.125 Safari/537.36
我的认证设置代码如下:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter
private final JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
private final UserService userDetailsService;
private final JwtRequestFilter jwtRequestFilter;
@Autowired
public WebSecurityConfig(
JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint,
UserService userDetailsService,
JwtRequestFilter jwtRequestFilter
)
super();
this.jwtAuthenticationEntryPoint = jwtAuthenticationEntryPoint;
this.userDetailsService = userDetailsService;
this.jwtRequestFilter = jwtRequestFilter;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception
auth.userDetailsService(this.userDetailsService).passwordEncoder(passwordEncoder());
@Bean
public PasswordEncoder passwordEncoder()
return new BCryptPasswordEncoder();
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception
return super.authenticationManagerBean();
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception
httpSecurity.csrf()
.disable()
.authorizeRequests()
.antMatchers("/auth", "/auth/validate")
.permitAll()
.anyRequest()
.authenticated()
.and()
.exceptionHandling()
.authenticationEntryPoint(this.jwtAuthenticationEntryPoint)
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
httpSecurity.addFilterBefore(this.jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
失败的客户端应用程序是 Angular 应用程序,从 auth 返回的 JWT 令牌存储为 cookie,然后拦截器检查 cookie,并通过拦截器将值(JWT 令牌)附加到请求标头。这种方法一直对我有用(如有必要,将提供代码)。下面的屏幕截图显示了完全相同的呼叫成功返回:
我感觉可能是在受保护的端点上不允许 OPTIONS 请求,但我没有证据表明是这种情况。是否有我可以使用的注释或实用程序允许我接受 OPTIONS 请求?这里有什么我做错了什么吗?我很茫然
【问题讨论】:
【参考方案1】:已修复 - 我刚刚将我的 HTTP 配置更新为:
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception
httpSecurity.headers().frameOptions().disable().and().cors().and().csrf().disable();
httpSecurity.addFilterBefore(this.jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
我现在可以在服务器端接受 OPTIONS 请求。
【讨论】:
以上是关于Spring/Boot - JWT 未在 GET 请求中获取的主要内容,如果未能解决你的问题,请参考以下文章