2017-02-20 16 views
9

मेरे पास एक अतिरिक्त एपीआई है जहां मैं वसंत सुरक्षा मूल प्रमाणीकरण का उपयोग करके प्रमाणीकरण कर रहा हूं जहां ग्राहक प्रत्येक अनुरोध के लिए उपयोगकर्ता नाम और पासवर्ड भेजता है। अब, मैं टोकन आधारित प्रमाणीकरण को कार्यान्वित करना चाहता हूं, जहां मैं पहली बार प्रमाणीकृत होने पर प्रतिक्रिया शीर्षलेख में टोकन भेजूंगा। आगे के अनुरोधों के लिए, क्लाइंट उस शीर्षलेख में टोकन शामिल कर सकता है जिसका उपयोग उपयोगकर्ता को संसाधनों को प्रमाणीकृत करने के लिए किया जाएगा। मैं दो प्रमाणीकरण प्रदाताओं 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 ==)

लेकिन जब मैं हैडर एक्स प्राधि-टोकन (जो Constants.AUTH_HEADER_NAME है) का उपयोग करने में टोकन शामिल, 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); 
} 

कृपया सुझाव दें कि मैं वसंत सुरक्षा के वर्तमान व्यवहार को प्रभावित किए बिना टोकन आधारित प्रमाणीकरण को कैसे कार्यान्वित कर सकता हूं।

+0

आपके पास ऐसा करने के विभिन्न तरीके हैं, आप प्रदाता को प्रत्येक फ़िल्टर पर सीधे प्रयुक्त कर सकते हैं, या प्रदाता को एक प्रमाणीकरण प्रबंधक में सेट कर सकते हैं, और दोनों FIlters में इसके साथ काम कर सकते हैं। बेशक, आपको वसंत सुरक्षा फ़िल्टरChain में दोनों फ़िल्टर सेट करना होगा। – Dani

उत्तर

11

यहाँ कैसे मैं टोकन आधारित प्रमाणीकरण और बुनियादी प्रमाणीकरण

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 कॉन्फ़िगर किया गया है और वसंत सुरक्षा के लिए फिल्टर के रूप में जोड़ा,

जब भी बुनियादी प्रमाणीकरण सफल अनुरोध onSuccessfulAuthentication जहाँ हम स्थापित करने के लिए पुनः निर्देशित किया जाएगा है टोकन और इसे कुछ शीर्षलेख "हेडर-नाम" के साथ प्रतिक्रिया में भेजें।

यदि आगे के अनुरोध के लिए "हेडर-नाम" भेजा जाता है, तो अनुरोध मूल प्रमाणीकरण को आजमाने का प्रयास करने से पहले टोकन प्रमाणीकरण फ़िल्टर के माध्यम से जाएगा।

+0

तो टोकन प्रमाणीकरण सफल होने पर भी, यह बुनियादी प्रमाणीकरण के साथ-साथ सही कोशिश करेगा? क्योंकि यह एक और फिल्टर है। इससे क्या बात है? उसे हर बार उपयोगकर्ता/पासवर्ड भेजने की ज़रूरत है? – selman

+0

@selman उसे हर बार उपयोगकर्ता/पासवर्ड भेजने की आवश्यकता नहीं है।['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) इस तरह कार्यान्वित किया गया है कि अगर अनुरोध में मूल प्रमाणीकरण हेडर नहीं है, तो यह केवल अगले फ़िल्टर में पास-थ्रू होगा। इसलिए, वास्तव में दोनों फ़िल्टर एक ही अनुरोध के लिए काम करेंगे, अगर इस अनुरोध में टोकन हेडर और मूल ऑथ हेडर दोनों हैं। और इस मामले में मूल लेख शीर्षलेख जीतता है (क्योंकि यह आखिरी है)। – djxak

+0

@selman अगर टोकन हेडर के साथ अनुरोध से जुड़ा वैध टोकन है। यह मूल लेख फ़िल्टर के माध्यम से नहीं जाता है। दो मामले हैं कि दोनों फ़िल्टर निष्पादित किए जाएंगे। यदि अनुरोध में टोकन हेडर 2 शामिल नहीं है। यदि टोकन अमान्य/समाप्त हो गया है जो मूल प्रमाणीकरण फ़िल्टर शुरू करेगा और आप मूल प्रमाणीकरण फ़िल्टर में टोकन सेट कर सकते हैं आगे के अनुरोधों के लिए इस्तेमाल किया जा सकता है। – Raghavendra

1

आप उदाहरण के लिए, अपने प्रमाणीकरण फिल्टर में अपने कस्टम 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); 
    } 
} 
+0

हाय, उत्तर के लिए धन्यवाद। मैंने आपके द्वारा उल्लिखित तरीके के समान समाधान प्राप्त किया। मैं जल्द ही समाधान पोस्ट कर रहा हूँ। – Raghavendra

संबंधित मुद्दे