2017-02-20 23 views
9

Tôi có api còn lại trong đó tôi đang xác thực bằng bảo mật mùa xuân Cấp phép cơ bản trong đó máy khách gửi tên người dùng và mật khẩu cho mỗi yêu cầu. Bây giờ, tôi muốn triển khai xác thực dựa trên mã thông báo nơi tôi sẽ gửi mã thông báo trong tiêu đề phản hồi khi người dùng được xác thực lúc đầu. Đối với các yêu cầu thêm, khách hàng có thể bao gồm mã thông báo đó trong tiêu đề sẽ được sử dụng để xác thực người dùng với tài nguyên. Tôi có hai nhà cung cấp chứng thực tokenAuthenticationProvider và daoAuthenticationProviderXác thực dựa trên mã thông báo bảo mật mùa xuân

@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); 
     } 
} 

Và trong daoAuthenticationProvider Tôi đang thiết userDetailsService tùy chỉnh và xác thực đối với thông tin đăng nhập người dùng bằng cách lấy nó ra khỏi cơ sở dữ liệu (được làm việc tốt miễn là tên người dùng và mật khẩu được thông qua sử dụng ủy quyền: bGllQXBpVXNlcjogN21wXidMQjRdTURtR04pag Basic == như tiêu đề)

Nhưng khi tôi bao gồm thẻ trong tiêu đề sử dụng X-AUTH-TOKEN (đó là Constants.AUTH_HEADER_NAME), tokenAuthenticationProvider không được gọi. Tôi gặp lỗi dưới dạng

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

Và đây là cách tôi thêm nhà cung cấp xác thực.

@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); 
} 

Vui lòng đề xuất cách triển khai xác thực dựa trên mã thông báo mà không làm tổn hại đến hành vi hiện tại của bảo mật mùa xuân.

+0

Bạn có nhiều cách khác nhau để làm điều này, Bạn có thể @Autowired nhà cung cấp trực tiếp trên mỗi Bộ lọc hoặc đặt Nhà cung cấp đó trong một Trình quản lý xác thực và làm việc với nó trong cả hai FIlters. Tất nhiên, bạn phải thiết lập cả hai bộ lọc trong Spring Security FilterChain. – Dani

Trả lời

11

Sau đây là cách tôi đã có thể thực hiện thẻ based authentication và xác thực cơ bản

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"); 


    } 

} 

Như CustomBasicAuthenticationFilter của chúng tôi đã được cấu hình và thêm vào như là một bộ lọc đối với an ninh mùa xuân,

Bất cứ khi nào xác thực cơ bản là thành công theo yêu cầu sẽ được chuyển đến onSuccessfulAuthentication nơi chúng tôi đặt mã thông báo và gửi nó trong phản hồi với một số tiêu đề "header-name".

Nếu "tên tiêu đề" được gửi để yêu cầu thêm, thì yêu cầu sẽ đi qua TokenAuthenticationFilter trước tiên trước khi thử dùng Xác thực cơ bản.

+0

Vì vậy, ngay cả khi Xác thực mã thông báo thành công, nó cũng sẽ thử xác thực cơ bản đúng không? Bởi vì đó là một bộ lọc khác.Điểm là gì? Anh ấy cần phải gửi người dùng/mật khẩu mỗi lần? – selman

+0

@selman Anh ấy không cần phải gửi người dùng/mật khẩu mỗi lần.['BasicAuthenticationFilter'] (https://github.com/spring-projects/spring-security/blob/5.0.1.RELEASE/web/src/main/java/org/springframework/security/web/authentication/www /BasicAuthenticationFilter.java#L157) được triển khai theo cách như vậy, nếu yêu cầu không có tiêu đề xác thực cơ bản, nó chỉ chuyển qua bộ lọc tiếp theo. Vì vậy, trên thực tế cả hai bộ lọc sẽ hoạt động cho cùng một yêu cầu chỉ trong trường hợp yêu cầu này có cả tiêu đề mã thông báo và tiêu đề xác thực cơ bản. Và trong trường hợp này, tiêu đề auth cơ bản sẽ thắng (vì nó là cuối cùng). – djxak

+0

@selman nếu có mã thông báo hợp lệ được đính kèm với yêu cầu với tiêu đề mã thông báo. Nó không đi qua bộ lọc auth cơ bản. Có hai trường hợp cả hai bộ lọc sẽ được thực thi 1. Nếu yêu cầu không chứa tiêu đề mã thông báo 2. Nếu mã thông báo không hợp lệ/hết hạn sẽ khởi tạo bộ lọc xác thực cơ bản và bạn có thể đặt mã thông báo trong bộ lọc xác thực cơ bản có thể được sử dụng cho các yêu cầu khác. – Raghavendra

1

Bạn có thể thử thiết lập thẻ tùy chỉnh AuthenticationToken của bạn trong bộ lọc xác thực của bạn, ví dụ:

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); 
    } 
} 
+0

Xin chào, Cảm ơn bạn đã trả lời. Tôi đã đạt được giải pháp tương tự như cách bạn đã đề cập. Tôi sẽ sớm đăng giải pháp. – Raghavendra

Các vấn đề liên quan