基于Spring Security Token的身份validation

我有一个restapi,我在使用spring security Basic Authorization进行身份validation,其中客户端为每个请求发送用户名和密码。 现在,我想实现基于令牌的身份validation,我将在用户首先进行身份validation时在响应头中发送令牌。 对于进一步的请求,客户端可以在标头中包含该标记,该标记将用于向用户validation资源。 我有两个身份validation提供程序tokenAuthenticationProvider和daoAuthenticationProvider

@Component public class TokenAuthenticationProvider implements AuthenticationProvider { @Autowired private TokenAuthentcationService service; @Override public Authentication authenticate(final Authentication authentication) throws AuthenticationException { final RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); final HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest(); final String token = request.getHeader(Constants.AUTH_HEADER_NAME); final Token tokenObj = this.service.getToken(token); final AuthenticationToken authToken = new AuthenticationToken(tokenObj); return authToken; } @Override public boolean supports(final Class authentication) { return AuthenticationToken.class.isAssignableFrom(authentication); } } 

在daoAuthenticationProvider中,我设置自定义userDetailsS​​ervice并通过从数据库中获取用户登录详细信息进行身份validation(只要使用授权传递用户名和密码就可以正常工作:基本bGllQXBpVXNlcjogN21wXidMQjRdTURtR04pag ==作为标头)

但是当我使用X-AUTH-TOKEN(即Constants.AUTH_HEADER_NAME)在标头中包含token时,不会调用tokenAuthenticationProvider。 我收到错误了

 {"timestamp":1487626368308,"status":401,"error":"Unauthorized","message":"Full authentication is required to access this resource","path":"/find"} 

以下是我添加身份validation提供程序的方法。

  @Override public void configure(final AuthenticationManagerBuilder auth) throws Exception { final UsernamePasswordAuthenticationProvider daoProvider = new UsernamePasswordAuthenticationProvider(this.service, this.passwordEncoder()); auth.authenticationProvider(this.tokenAuthenticationProvider); auth.authenticationProvider(daoProvider); } 

请建议如何在不损害spring安全性的当前行为的情况下实现基于令牌的身份validation。

以下是我能够实现基于令牌的身份validation和基本身份validation的方法

SpringSecurityConfig.java

 @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override public void configure(final AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(this.participantService).passwordEncoder(this.passwordEncoder()); } @Override protected void configure(final HttpSecurity http) throws Exception { //Implementing Token based authentication in this filter final TokenAuthenticationFilter tokenFilter = new TokenAuthenticationFilter(); http.addFilterBefore(tokenFilter, BasicAuthenticationFilter.class); //Creating token when basic authentication is successful and the same token can be used to authenticate for further requests final CustomBasicAuthenticationFilter customBasicAuthFilter = new CustomBasicAuthenticationFilter(this.authenticationManager() ); http.addFilter(customBasicAuthFilter); } } 

TokenAuthenticationFilter.java

  public class TokenAuthenticationFilter extends GenericFilterBean { @Override public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException { final HttpServletRequest httpRequest = (HttpServletRequest)request; //extract token from header final String accessToken = httpRequest.getHeader("header-name"); if (null != accessToken) { //get and check whether token is valid ( from DB or file wherever you are storing the token) //Populate SecurityContextHolder by fetching relevant information using token final User user = new User( "username", "password", true, true, true, true, authorities); final UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities()); SecurityContextHolder.getContext().setAuthentication(authentication); } chain.doFilter(request, response); } } 

CustomBasicAuthenticationFilter.java

 @Component public class CustomBasicAuthenticationFilter extends BasicAuthenticationFilter { @Autowired public CustomBasicAuthenticationFilter(final AuthenticationManager authenticationManager) { super(authenticationManager); } @Override protected void onSuccessfulAuthentication(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response, final Authentication authResult) { //Generate Token //Save the token for the logged in user //send token in the response response.setHeader("header-name" , "token"); } } 

由于我们的CustomBasicAuthenticationFilter已经配置并添加为弹簧安全性的filter,

每当基本身份validation成功时,请求将被重定向到onSuccessfulAuthentication,我们在其中设置令牌并将其发送到响应中,并带有一些标题“header-name”。

如果发送“header-name”以进一步请求,则在尝试尝试基本身份validation之前,请求将首先通过TokenAuthenticationFilter。

您可以尝试在身份validationfilter中设置自定义AuthenticationToken令牌,例如:

 public class AuthenticationFilter extends GenericFilterBean { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { final String authTokenHeader = ((HttpServletRequest)request).getHeader(Constants.AUTH_HEADER_NAME); if (authTokenHeader != null) { SecurityContextHolder.getContext().setAuthentication(createAuthenticationToken(authTokenHeader)); } chain.doFilter( request, response ); } }