spring-security - GIT上下载spring-boot-security 集成JWT例子,为何一次请求会触发两次认证处理?
问题描述
《测试项目来源地址:https://codeload.github.com/s...》
以下代码说明:
1、security configuration:
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
public static final String JWT_TOKEN_HEADER_PARAM = "X-Authorization";
public static final String FORM_BASED_LOGIN_ENTRY_POINT = "/api/auth/login";
public static final String TOKEN_BASED_AUTH_ENTRY_POINT = "/api/**";
public static final String TOKEN_REFRESH_ENTRY_POINT = "/api/auth/token";
@Bean
protected JwtTokenAuthenticationProcessingFilter buildJwtTokenAuthenticationProcessingFilter() throws Exception {
List<String> pathsToSkip = Arrays.asList(TOKEN_REFRESH_ENTRY_POINT, FORM_BASED_LOGIN_ENTRY_POINT);
SkipPathRequestMatcher matcher = new SkipPathRequestMatcher(pathsToSkip, TOKEN_BASED_AUTH_ENTRY_POINT);
JwtTokenAuthenticationProcessingFilter filter
= new JwtTokenAuthenticationProcessingFilter(failureHandler, tokenExtractor, matcher);
filter.setAuthenticationManager(this.authenticationManager);
return filter;
}
protected void configure(AuthenticationManagerBuilder auth) {
auth.authenticationProvider(ajaxAuthenticationProvider);
auth.authenticationProvider(jwtAuthenticationProvider); //JWT TOKEN认证Provider
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable() // We don't need CSRF for JWT based authentication
.exceptionHandling()
.authenticationEntryPoint(this.authenticationEntryPoint)
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers(FORM_BASED_LOGIN_ENTRY_POINT).permitAll() // Login end-point
.antMatchers(TOKEN_REFRESH_ENTRY_POINT).permitAll() // Token refresh end-point
.and()
.authorizeRequests()
.antMatchers(TOKEN_BASED_AUTH_ENTRY_POINT).authenticated() // Protected API End-points
.and()
.addFilterBefore(buildJwtTokenAuthenticationProcessingFilter(), UsernamePasswordAuthenticationFilter.class)
}
}
2、认证处理filter
public class JwtTokenAuthenticationProcessingFilter extends AbstractAuthenticationProcessingFilter {
private final AuthenticationFailureHandler failureHandler;
private final TokenExtractor tokenExtractor;
@Autowired
public JwtTokenAuthenticationProcessingFilter(AuthenticationFailureHandler failureHandler,
TokenExtractor tokenExtractor, RequestMatcher matcher) {
super(matcher);
this.failureHandler = failureHandler;
this.tokenExtractor = tokenExtractor;
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException, IOException, ServletException {
String tokenPayload = request.getHeader(WebSecurityConfig.JWT_TOKEN_HEADER_PARAM);
RawAccessJwtToken token = new RawAccessJwtToken(tokenExtractor.extract(tokenPayload));
System.out.println("****attemptAuthentication***一次请求会产生两次认证****:"+request.getServletPath());
return getAuthenticationManager().authenticate(new JwtAuthenticationToken(token));
}
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
Authentication authResult) throws IOException, ServletException {
SecurityContext context = SecurityContextHolder.createEmptyContext();
context.setAuthentication(authResult);
SecurityContextHolder.setContext(context);
chain.doFilter(request, response);
}
}
3、资源测试类:
@RestController
public class ProfileEndpoint {
@RequestMapping(value="/api/me", method=RequestMethod.GET)
public @ResponseBody UserContext get(JwtAuthenticationToken token) {
return (UserContext) token.getPrincipal();
}
}
4、POSTMAN调试:
GET /api/me HTTP/1.1
Host: localhost:9966
X-Requested-With: XMLHttpRequest
Cache-Control: no-cache
X-Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJzdmxhZGFAZ21haWwuY29tIiwic2NvcGVzIjpbIlJPTEVfQURNSU4iLCJST0xFX1BSRU1JVU1fTUVNQkVSIl0sImlzcyI6Imh0dHA6Ly9zdmxhZGEuY29tIiwiaWF0IjoxNDgyNzI3NDc0LCJleHAiOjE0ODI3MjgzNzR9.K938npXPsNSBrKcdrGoFVsSsEYPUEWQROWpU9Kbw4P_hxyvMVYh2IuwkZbA4E0jwwpnMafjZ1P-Z5Y-tcYdGJw
返回:UserContext 对象;
**每次带合法的TOKEN请求, 发现: JwtTokenAuthenticationProcessingFilter类中attemptAuthentication被两次执行,感觉这个FILTER被装载了两次,理解不来;请SPRING SECURITY的大牛解惑。
@Bean
protected JwtTokenAuthenticationProcessingFilter buildJwtTokenAuthenticationProcessingFilter() throws Exception {
List<String> pathsToSkip = Arrays.asList(TOKEN_REFRESH_ENTRY_POINT, FORM_BASED_LOGIN_ENTRY_POINT);
SkipPathRequestMatcher matcher = new SkipPathRequestMatcher(pathsToSkip, TOKEN_BASED_AUTH_ENTRY_POINT);
JwtTokenAuthenticationProcessingFilter filter
= new JwtTokenAuthenticationProcessingFilter(failureHandler, tokenExtractor, matcher);
filter.setAuthenticationManager(this.authenticationManager);
return filter;
}
取消 @Bean 注解,问题就可以解决;原因:注解后Applicationcontext自动扫描后装载Filter, addFilterBefore也会new Filter, 两个同样FILTER被加载两次,导致两次执行,MARK!
这篇关于spring-security - GIT上下载spring-boot-security 集成JWT例子,为何一次请求会触发两次认证处理?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!