Java 具有permitAll()和过期身份验证令牌的URL的Spring安全性
我将Spring4与SpringSecurity、自定义GenericFilterBean和AuthenticationProvider实现一起使用。除了创建新会话的URL之外,我的URL大多是安全的:/v2/session(例如,基于用户名和密码登录,并返回需要验证的后续请求中使用的身份验证令牌),配置如下:Java 具有permitAll()和过期身份验证令牌的URL的Spring安全性,java,spring,security,authentication,spring-security,Java,Spring,Security,Authentication,Spring Security,我将Spring4与SpringSecurity、自定义GenericFilterBean和AuthenticationProvider实现一起使用。除了创建新会话的URL之外,我的URL大多是安全的:/v2/session(例如,基于用户名和密码登录,并返回需要验证的后续请求中使用的身份验证令牌),配置如下: @Configuration @ComponentScan(basePackages={"com.api.security"}) @EnableWebSecurity public cl
@Configuration
@ComponentScan(basePackages={"com.api.security"})
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private ApiAuthenticationProvider apiAuthenticationProvider;
@Autowired
private AuthTokenHeaderAuthenticationFilter authTokenHeaderAuthenticationFilter;
@Autowired
private AuthenticationEntryPoint apiAuthenticationEntryPoint;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
auth.authenticationProvider(apiAuthenticationProvider);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.addFilterBefore(authTokenHeaderAuthenticationFilter, BasicAuthenticationFilter.class) // Main auth filter
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.authorizeRequests()
.antMatchers(HttpMethod.POST, "/v2/session").permitAll()
.anyRequest().authenticated();
http.exceptionHandling()
.authenticationEntryPoint(apiAuthenticationEntryPoint);
}
}
authTokenHeaderAuthenticationFilter对每个请求运行,并从请求头获取令牌:
/**
* Main Auth Filter. Always sets Security Context if the Auth token Header is not empty
*/
@Component
public class AuthTokenHeaderAuthenticationFilter extends GenericFilterBean {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
final String token = ((HttpServletRequest) request).getHeader(RequestHeaders.AUTH_TOKEN_HEADER);
if (StringUtils.isEmpty(token)) {
chain.doFilter(request, response);
return;
}
try {
AuthenticationToken authRequest = new AuthenticationToken(token);
SecurityContextHolder.getContext().setAuthentication(authRequest);
}
} catch (AuthenticationException failed) {
SecurityContextHolder.clearContext();
return;
}
chain.doFilter(request, response); // continue down the chain
}
}
自定义APAuthenticationProvider将尝试根据标头中提供的令牌对所有请求进行身份验证,如果身份验证失败,则抛出AccessException,客户端将收到HTTP 401响应:
@Component
public class ApiAuthenticationProvider implements AuthenticationProvider {
@Autowired
private remoteAuthService remoteAuthService;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
AuthenticationToken authRequest = (AuthenticationToken) authentication;
String identity = null;
try {
identity = remoteAuthService.getUserIdentityFromToken(authRequest.getToken());
} catch (AccessException e) {
throw new InvalidAuthTokenException("Cannot get user identity from the token", e);
}
return new AuthenticationToken(identity, authRequest.getToken(), getGrantedAuthorites());
}
}
这对于需要身份验证的请求来说非常有效。这适用于/v2/session请求,其中没有身份验证头。但是,对于头中(或cookie中-代码示例中未显示;如果客户端未清除头或继续发送cookie和请求,有时可能会发生这种情况)具有过期身份验证令牌的/v2/session请求安全上下文将被初始化,APAuthenticationProvider将抛出异常并用HTTP 401响应客户端
由于/v2/会话已配置为
http.authorizeRequests()
.antMatchers(HttpMethod.POST, "/v2/session").permitAll()
我希望Spring安全性在调用ApiAuthenticationProvider.authenticate()之前确定这一点。对于配置为permitAll()的URL,筛选器或身份验证提供程序应以何种方式忽略/不引发异常?在执行请求授权检查之前,会触发Spring安全筛选器。为了使授权检查起作用,假设请求已通过过滤器,并且已设置Spring安全上下文(或未设置,取决于是否传入了身份验证凭据) 在过滤器中,如果令牌不存在,则检查是否继续进行过滤器链处理。不幸的是,如果是,那么它将被传递给您的提供者进行身份验证,这会引发一个异常,因为令牌已过期,因此您将获得401 <>你最好绕过你认为公共的URL的过滤器执行。您可以在过滤器本身或配置类中执行此操作。将以下方法添加到您的
SecurityConfig
类:
@Override
public void configure(WebSecurity webSecurity) {
webSecurity.ignoring().antMatchers(HttpMethod.POST, "/v2/session");
}
这样做的目的是完全绕过
AuthTokenHeaderAuthenticationFilter
进行POST/v2/sessions
URL。检查此线程,它还回答了您的问题:@grigori如何确保我的请求仍然通过安全筛选链的其余部分,例如csrf保护等。然后我需要将该URL保存在permitAll()中。正确的?总之,我将如何配置需要其余spring安全过滤器链服务的公共请求?3年了,仍然不是一个更好的解决方案,这让我有点担心!