首页 文章

基于Spring Security Token的身份验证

提问于
浏览
17

我有一个休息api,我在使用spring security Basic Authorization进行身份验证,其中客户端为每个请求发送用户名和密码 . 现在,我想实现基于令牌的身份验证,我将在用户首先进行身份验证时在响应头中发送令牌 . 对于进一步的请求,客户端可以在标头中包含该标记,该标记将用于向用户验证资源 . 我有两个身份验证提供程序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中,我设置自定义userDetailsService并通过从数据库中获取用户登录详细信息进行身份验证(只要使用授权传递用户名和密码,该工作正常:基本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"}

以下是我添加身份验证提供程序的方法 .

@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安全性的当前行为的情况下实现基于令牌的身份验证 .

2 回答

  • 17

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

    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已经配置并添加为 spring 安全性的过滤器,

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

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

  • 2

    您可以尝试在身份验证过滤器中设置自定义 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 );
        }
    }
    

相关问题