我有一个Spring / Boot REST API,该API为会话提供JWT令牌。
我有一个使用2种方法的会话端点,一种用于验证用户身份,一种用于验证Auth令牌。我可以在端点上成功创建和验证令牌(这些令牌上没有过滤器)。一旦尝试使用客户端应用程序访问端点,请求就会爆炸,但是我可以将它们很好地用于像失眠之类的REST客户端。
在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请求?我在这里做过任何公然错误的事情吗?我很茫然
答案 0 :(得分:0)
已修复-我刚刚将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请求。