2015-04-18 10 views
5

मैं oAuth2 संरक्षित सेवाओं का एक सेट खा रहा हूं। यह वर्तमान में इस तरह काम करता है: ग्राहक अपने उपयोगकर्ता नाम और पासवर्ड का उपयोग करने में लॉग इन करता है। मैं इन्हें टोकन के लिए बदलता हूं। मैं सत्र में टोकन रखता हूं और हर बार इसे एक सेवा कॉल करना चाहता हूं। यह काम करता है, लेकिन समस्या यह है कि मैं वसंत सुरक्षा oAuth2 समर्थन का उपयोग किए बिना इसे पूरी तरह से मैन्युअल रूप से करता हूं। यह इस प्रकार से दिखाई देता है:ओएथ 2 क्लाइंट स्प्रिंग सिक्योरिटी में पासवर्ड अनुदान के साथ

<!-- Configure Authentication mechanism --> 
<authentication-manager alias="authenticationManager"> 
    <authentication-provider ref="oAuth2AuthenticationProvider"/> 
</authentication-manager> 


<beans:bean id="oAuth2AuthenticationProvider" class="my.custom.Oauth2AuthenticationProvider"> 
    <beans:constructor-arg name="accessTokenUri" value="http://x.x.x.x/oauth/token"/> 
    <beans:constructor-arg name="clientId" value="myClientId"/> 
    <beans:constructor-arg name="clientSecret" value="myClientSecret"/> 
    <beans:constructor-arg name="scope"> 
     <beans:list> 
      <beans:value>myScope</beans:value> 
     </beans:list> 
    </beans:constructor-arg> 
</beans:bean> 

<beans:bean id="resourceOwnerPasswordAccessTokenProvider" class="org.springframework.security.oauth2.client.token.grant.password.ResourceOwnerPasswordAccessTokenProvider"/> 

आप देख सकते हैं मैं अपने आप को प्रमाणीकरण प्रदाता बना दिया। यह मानक उपयोगकर्ता नाम पासवर्ड स्वीकार कर रहा है, लेकिन यह मेरा स्वयं का विस्तार कर रहा है जो वास्तविक OAuth2AccessToken को भी रखता है, इस प्रकार सुरक्षा संदर्भ में रहता है।

public class Oauth2AuthenticationProvider implements AuthenticationProvider { 

@Autowired 
private ResourceOwnerPasswordAccessTokenProvider provider; 

private String accessTokenUri; 
private String clientId; 
private String clientSecret; 
private List<String> scope; 

public Oauth2AuthenticationProvider(String accessTokenUri, String clientId, String clientSecret, List<String> scope) { 
    this.accessTokenUri = accessTokenUri; 
    this.clientId = clientId; 
    this.clientSecret = clientSecret; 
    this.scope = scope; 
} 

@Override 
public Authentication authenticate(Authentication authentication) throws AuthenticationException { 
    String username = authentication.getName(); 
    String password = authentication.getCredentials().toString(); 
    OAuth2AccessToken token = obtainToken(username, password); 
    return handleLogonSuccess(authentication, token); 
} 

private OAuth2AccessToken obtainToken(String username, String password) { 
    ResourceOwnerPasswordResourceDetails passwordResourceDetails = new ResourceOwnerPasswordResourceDetails(); 
    passwordResourceDetails.setUsername(username); 
    passwordResourceDetails.setPassword(password); 
    passwordResourceDetails.setClientId(clientId); 
    passwordResourceDetails.setClientSecret(clientSecret); 
    passwordResourceDetails.setScope(scope); 
    passwordResourceDetails.setAccessTokenUri(accessTokenUri); 
    DefaultAccessTokenRequest defaultAccessTokenRequest = new DefaultAccessTokenRequest(); 
    OAuth2AccessToken token; 
    try { 
     token = provider.obtainAccessToken(passwordResourceDetails, defaultAccessTokenRequest); 
    } catch (OAuth2AccessDeniedException accessDeniedException) { 
     throw new BadCredentialsException("Invalid credentials", accessDeniedException); 
    } 

    return token; 
} 

public OAuth2AccessToken refreshToken(OAuth2AuthenticationToken authentication) { 
    OAuth2AccessToken token = authentication.getoAuth2AccessToken(); 
    OAuth2RefreshToken refreshToken = token.getRefreshToken(); 
    BaseOAuth2ProtectedResourceDetails resourceDetails = new BaseOAuth2ProtectedResourceDetails(); 
    resourceDetails.setClientId(clientId); 
    resourceDetails.setClientSecret(clientSecret); 
    resourceDetails.setScope(scope); 
    resourceDetails.setAccessTokenUri(accessTokenUri); 
    OAuth2AccessToken newToken = provider.refreshAccessToken(resourceDetails, refreshToken, new DefaultAccessTokenRequest()); 
    authentication.setoAuth2AccessToken(newToken); 
    return newToken; 
} 

public boolean supports(Class<?> authentication) { 
    return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication); 
} 

private Authentication handleLogonSuccess(Authentication authentication, OAuth2AccessToken token) { 

    MyCustomOAuth2AuthenticationToken successAuthenticationToken = new MyCustomOAuth2AuthenticationToken(user, authentication.getCredentials(), calculateAuthorities(authentication), token); 

    return successAuthenticationToken; 
} 

public list<GrantedAuthority> calculateAuthorities(Authentication authentication) { 
     //my custom logic that assigns the correct role. e.g. ROLE_USER 
} 

}

जैसा कि आप देख, यह मूल रूप से यकीन है कि टोकन से जहाँ मैं बस इसे बैक-एंड सेवाओं की प्रत्येक कॉल से पहले मैन्युअल रूप से निकाल सकते हैं सुरक्षा दायरे में रहता है बनाता है। इसी तरह, मैं प्रत्येक कॉल से पहले टोकन की ताजगी की जांच करूंगा। यह अच्छी तरह से काम करता है, लेकिन मुझे यकीन है कि मैं एक्सएमएल में स्प्रिंग के ओथ नेमस्पेस का उपयोग कर सकता हूं (मैं जावा कॉन्फ़िगरेशन का उपयोग नहीं कर रहा हूं) इसे अधिक-कॉन्फ़िगर-कम-कोड तरीके से प्राप्त करने के लिए। मुझे लगता है कि अधिकांश उदाहरणों में ओथ सर्वर कार्यान्वयन शामिल है, जिसकी मुझे परवाह नहीं है और बस मुझे भ्रमित करें।

क्या कोई मेरी मदद कर सकता है?

उत्तर

3

मैंने वसंत सुरक्षा ओएथ स्रोतों और बिट्स और ऑनलाइन पाए गए अन्य समाधानों के टुकड़ों को ब्राउज़ करने से एक समान समाधान किया है। मैं जावा कॉन्फ़िग उपयोग कर रहा हूँ, लेकिन शायद यह आप एक एक्सएमएल विन्यास के लिए नक्शे मदद कर सकते हैं, यहाँ यह जाता है:

@Configuration 
@EnableOAuth2Client 
public class RestClientConfig { 

    @Value("${http.client.maxPoolSize}") 
    private Integer maxPoolSize; 

    @Value("${oauth2.resourceId}") 
    private String resourceId; 

    @Value("${oauth2.clientId}") 
    private String clientId; 

    @Value("${oauth2.clientSecret}") 
    private String clientSecret; 

    @Value("${oauth2.accessTokenUri}") 
    private String accessTokenUri; 


    @Autowired 
    private OAuth2ClientContext oauth2ClientContext; 


    @Bean 
    public ClientHttpRequestFactory httpRequestFactory() { 
     return new HttpComponentsClientHttpRequestFactory(httpClient()); 
    } 

    @Bean 
    public HttpClient httpClient() { 
     PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(); 
     connectionManager.setMaxTotal(maxPoolSize); 
     // This client is for internal connections so only one route is expected 
     connectionManager.setDefaultMaxPerRoute(maxPoolSize); 
     return HttpClientBuilder.create().setConnectionManager(connectionManager).build(); 
    } 

    @Bean 
    public OAuth2ProtectedResourceDetails oauth2ProtectedResourceDetails() { 
     ResourceOwnerPasswordResourceDetails details = new ResourceOwnerPasswordResourceDetails(); 
     details.setId(resourceId); 
     details.setClientId(clientId); 
     details.setClientSecret(clientSecret); 
     details.setAccessTokenUri(accessTokenUri); 
     return details; 
    } 

    @Bean 
    public AccessTokenProvider accessTokenProvider() { 
     ResourceOwnerPasswordAccessTokenProvider tokenProvider = new ResourceOwnerPasswordAccessTokenProvider(); 
     tokenProvider.setRequestFactory(httpRequestFactory()); 
     return new AccessTokenProviderChain(
        Arrays.<AccessTokenProvider> asList(tokenProvider) 
       ); 
    } 

    @Bean 
    public OAuth2RestTemplate restTemplate() { 
     OAuth2RestTemplate template = new OAuth2RestTemplate(oauth2ProtectedResourceDetails(), oauth2ClientContext); 
     template.setRequestFactory(httpRequestFactory()); 
     template.setAccessTokenProvider(accessTokenProvider()); 
     return template; 
    } 
} 

एक महत्वपूर्ण बिट मैंने पाया कि आप स्वत: अन्यथा एक भी प्रदाता के लिए AccessTokenProviderChain उपयोग करने की आवश्यकता है टोकन रीफ्रेश (प्रमाणीकरण के बाद) काम नहीं करेगा।

पहले अनुरोध पर उपयोगकर्ता क्रेडेंशियल सेट करने के लिए आप इस की आवश्यकता होगी:

String url = "http://localhost:{port}/api/users/search/findByUsername?username={username}"; 

    ResponseEntity<User> responseEntity = restTemplate.getForEntity(
      url, User.class, 8081, username); 

यदि आप चाहते हैं:

@Autowired 
private OAuth2RestTemplate restTemplate; 

restTemplate.getOAuth2ClientContext().getAccessTokenRequest().set("username", username); 
restTemplate.getOAuth2ClientContext().getAccessTokenRequest().set("password", password); 

तो फिर तुम RestTemplate तरीकों, जैसे का उपयोग कर के रूप में सामान्य अनुरोध जारी कर सकते हैं तार पर अनुरोधों का पता लगाने के लिए आप apache http क्लाइंट पर लॉग स्तर सेट कर सकते हैं DEBUG, उदाहरण के लिए

logging.level.org.apache.http = डीबग

+0

क्या हुआ अगर यूज़रनेम और पासवर्ड पोस्ट शरीर में हैं: स्प्रिंग बूट के साथ? एक्स-www-url-encoded के रूप में – cosbor11

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