使用 jwt 在 springboot 中始终允许未经授权的请求
Posted
技术标签:
【中文标题】使用 jwt 在 springboot 中始终允许未经授权的请求【英文标题】:unauthorized request are always allowed in springboot using jwt 【发布时间】:2020-11-08 06:58:57 【问题描述】:我有一个项目,我启用了 jwt 以对其进行授权。问题是,每当我在标头中发送空标头请求或过期的授权代码时,它不会向我发送未经授权的错误,它会在日志中显示令牌无效但允许请求继续工作。这是我的配置代码:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter
@Autowired
private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
@Autowired
private UserDetailsService jwtUserDetailsService;
@Autowired
private JwtRequestFilter jwtRequestFilter;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception
// configure AuthenticationManager so that it knows from where to load
// user for matching credentials
// Use BCryptPasswordEncoder
auth.userDetailsService(jwtUserDetailsService).passwordEncoder(passwordEncoder());
@Bean
public PasswordEncoder passwordEncoder()
return new BCryptPasswordEncoder(BCryptVersion.$2Y);
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception
return super.authenticationManagerBean();
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception
httpSecurity.csrf().disable()
.authorizeRequests().antMatchers("/authenticate","/user","/swagger-ui.html","/swagger-ui/**"
,"/v3/api-docs/**").permitAll().
anyRequest().authenticated().and().
exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint).and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
httpSecurity.logout().logoutSuccessUrl("/authenticate").logoutUrl("/logout").permitAll();
@Override
public void configure(WebSecurity web) throws Exception
web.ignoring().mvcMatchers(String.valueOf(HttpMethod.OPTIONS), "/**");
// ignore swagger
web.ignoring().mvcMatchers("/swagger-ui.html/**", "/configuration/**", "/swagger-resources/**", "/v2/api-docs");
这是我的 jwt 请求过滤器:
@Component
public class JwtRequestFilter extends OncePerRequestFilter
@Autowired
private JwtUserDetailsService jwtUserDetailsService;
private JwtTokenUtil jwtTokenUtil;
public JwtRequestFilter(JwtTokenUtil jwtTokenUtil)
this.jwtTokenUtil = jwtTokenUtil;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException
final String requestTokenHeader = request.getHeader("Authorization");
String username = null;
String jwtToken = null;
// JWT Token is in the form "Bearer token". Remove Bearer word and get
// only the Token
if (requestTokenHeader != null && requestTokenHeader.startsWith("Bearer "))
jwtToken = requestTokenHeader.substring(7);
try
username = jwtTokenUtil.getUsernameFromToken(jwtToken);
catch (IllegalArgumentException e)
System.out.println("Unable to get JWT Token");
catch (ExpiredJwtException e)
System.out.println("JWT Token has expired");
else if (requestTokenHeader == null)
logger.info("Does not provide Authorization Header");
else if (!requestTokenHeader.startsWith("Bearer "))
logger.warn("JWT Token does not begin with Bearer");
// Once we get the token validate it.
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null)
UserDetails userDetails = this.jwtUserDetailsService.loadUserByUsername(username);
// if token is valid configure Spring Security to manually set
// authentication
if (jwtTokenUtil.validateToken(jwtToken, userDetails))
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
usernamePasswordAuthenticationToken
.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
// After setting the Authentication in the context, we specify
// that the current user is authenticated. So it passes the
// Spring Security Configurations successfully.
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
chain.doFilter(request, response);
最后是 JwtAuthenticationEntryPoint:
@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint, Serializable
private static final long serialVersionUID = -7858869558953243875L;
@Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
这是显示我没有在标头中发送任何令牌的日志,但它允许请求:
知道我应该怎么做吗? 有关更多信息,我应该说这段代码正在工作,但一段时间后停止工作,我没有找到任何原因,因为几个月来我没有对这些文件进行任何更改。
【问题讨论】:
您能提供假定受保护的端点吗? localhost:8080/api/customer/register 这是端点,但所有其他端点都相同。 【参考方案1】:您缺少 addFilterAfter 并更新您的代码,如下所示。
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception
httpSecurity.csrf().disable()
.authorizeRequests().antMatchers("/authenticate","/user","/swagger-ui.html","/swagger-ui/**"
,"/v3/api-docs/**").permitAll().
anyRequest().authenticated().and().
exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint).and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class).logout().logoutSuccessUrl("/authenticate").logoutUrl("/logout").permitAll();
请参考https://github.com/techiesantosh/taskmanager-service/blob/develop/src/main/java/com/web/taskmanager/config/TaskConfig.java
【讨论】:
很抱歉听到这个消息。但是 TaskConfig.java 和整个项目中的代码都经过了很好的测试并且可以正常工作。你能试着再调整一次,希望它可以工作。谢谢【参考方案2】:问题在于这一行的错误配置
web.ignoring().mvcMatchers(String.valueOf(HttpMethod.OPTIONS), "/**");
应该是
web.ignoring().mvcMatchers(HttpMethod.OPTIONS, "/**");
您现在可能已经注意到,您的配置实际上忽略了来自 Spring Security 过滤器的所有请求路径。这就是现在允许所有未经授权的请求(您期望的)的原因。
【讨论】:
谢谢,我删除了这一行,因为它不允许我删除 string.valueof。以上是关于使用 jwt 在 springboot 中始终允许未经授权的请求的主要内容,如果未能解决你的问题,请参考以下文章
Spring Boot 自定义 JWT 过滤器不允许任何没有令牌的请求