【发布时间】: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 请求?这里有什么我做错了什么吗?我很茫然
【问题讨论】:
标签: angular spring-boot rest authentication jwt