spring-oauth2原理及使用

来源:互联网 发布:网络集成版驱动精灵 编辑:程序博客网 时间:2024/06/07 18:26

spring-oauth2原理及使用

转自:http://patrick002.iteye.com/blog/2207795

spring-oauth2 (bearer)是基于spring-security的验证机制,对于第三方访问受限资源时通过token机制来验证

验证steps:



 
通过时序图来看一下,验证方式:

 

发送username, password, client_id, client_secret, grant_typeserver

 

server返回包括access_token, token_type, refresh_token, expires_in



 
其中,expires_in有效期,如果超期了,refresh_token起作用,如下:

使用refresh_token重新发起验证请求



 
来看一下,如何通过spring配置,完成上面的验证机制:

 

Xml代码  收藏代码
  1. <?xml version="1.0" encoding="UTF-8" ?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:oauth="http://www.springframework.org/schema/security/oauth2"  
  4.     xmlns:sec="http://www.springframework.org/schema/security" xmlns:mvc="http://www.springframework.org/schema/mvc"  
  5.     xmlns:context="http://www.springframework.org/schema/context"  
  6.     xsi:schemaLocation="http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2-1.0.xsd  
  7.         http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd  
  8.         http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd  
  9.         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd  
  10.         http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">  
  11.    
  12.     <sec:http pattern="/oauth/token" create-session="stateless"  
  13.         authentication-manager-ref="authenticationManager">  
  14.         <sec:intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY" />  
  15.         <sec:anonymous enabled="false" />  
  16.         <sec:http-basic entry-point-ref="clientAuthenticationEntryPoint" />  
  17.         <sec:custom-filter ref="clientCredentialsTokenEndpointFilter" before="BASIC_AUTH_FILTER" />  
  18.         <sec:access-denied-handler ref="oauthAccessDeniedHandler" />  
  19.     </sec:http>  
  20.    
  21.     <sec:http pattern="/protected/**" create-session="never"  
  22.         entry-point-ref="oauthAuthenticationEntryPoint">  
  23.         <sec:anonymous enabled="false" />  
  24.         <sec:intercept-url pattern="/protected/**" method="GET" access="IS_AUTHENTICATED_FULLY" />  
  25.         <sec:custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />  
  26.         <sec:access-denied-handler ref="oauthAccessDeniedHandler" />  
  27.     </sec:http>  
  28.    
  29.     <bean id="oauthAuthenticationEntryPoint"  
  30.         class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">  
  31.     </bean>  
  32.    
  33.     <bean id="clientAuthenticationEntryPoint"  
  34.         class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">  
  35.         <property name="realmName" value="springsec/client" />  
  36.         <property name="typeName" value="Basic" />  
  37.     </bean>  
  38.    
  39.     <bean id="oauthAccessDeniedHandler"  
  40.         class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler">  
  41.     </bean>  
  42.    
  43.     <bean id="clientCredentialsTokenEndpointFilter"  
  44.         class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">  
  45.         <property name="authenticationManager" ref="authenticationManager" />  
  46.     </bean>  
  47.    
  48.     <sec:authentication-manager alias="authenticationManager">  
  49.         <sec:authentication-provider user-service-ref="clientDetailsUserService" />  
  50.     </sec:authentication-manager>  
  51.    
  52.     <bean id="clientDetailsUserService"  
  53.         class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">  
  54.         <constructor-arg ref="clientDetails" />  
  55.     </bean>  
  56.    
  57.     <bean id="clientDetails" class="it.iol.oauthaaa.security.AAAGuestServiceImpl">  
  58.         <property name="id" value="mysupplycompany" />  
  59.         <property name="secretKey" value="mycompanykey" />  
  60.     </bean>  
  61.    
  62.     <sec:authentication-manager id="userAuthenticationManager">  
  63.         <sec:authentication-provider ref="customUserAuthenticationProvider" />  
  64.     </sec:authentication-manager>  
  65.    
  66.     <bean id="customUserAuthenticationProvider"  
  67.         class="it.iol.oauthaaa.security.AAAUserAuthenticationProvider">  
  68.     </bean>  
  69.    
  70.     <oauth:authorization-server  
  71.         client-details-service-ref="clientDetails" token-services-ref="tokenServices">  
  72.         <oauth:authorization-code />  
  73.         <oauth:implicit/>  
  74.         <oauth:refresh-token/>  
  75.         <oauth:client-credentials />  
  76.         <oauth:password authentication-manager-ref="userAuthenticationManager"/>  
  77.     </oauth:authorization-server>  
  78.    
  79.     <oauth:resource-server id="resourceServerFilter"  
  80.         resource-id="springsec" token-services-ref="tokenServices" />  
  81.    
  82.     <bean id="tokenStore"  
  83.         class="org.springframework.security.oauth2.provider.token.InMemoryTokenStore" />  
  84.    
  85.     <bean id="tokenServices"  
  86.         class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">  
  87.         <property name="tokenStore" ref="tokenStore" />  
  88.         <property name="supportRefreshToken" value="true" />  
  89.         <property name="accessTokenValiditySeconds" value="120"></property>  
  90.         <property name="clientDetailsService" ref="clientDetails" />  
  91.     </bean>  
  92.    
  93.     <mvc:annotation-driven />  
  94.    
  95.     <mvc:default-servlet-handler />  
  96.    
  97.     <context:annotation-config/>  
  98.    
  99.     <bean id="MyResource" class="it.iol.oauthaaa.resources.UserResource"></bean>  
  100.     <bean id="aaaProxy" class="it.iol.oauthaaa.security.AAAProxy"></bean  
  101. </beans>  

 通过发起/oauth/token 请求, filter拦截处理,具体代码:

 

 

Java代码  收藏代码
  1. @Service  
  2. public class AAAGuestServiceImpl implements ClientDetailsService {  
  3.    
  4.     private String id;  
  5.     private String secretKey;  
  6.    
  7.     @Override  
  8.     public ClientDetails loadClientByClientId(String clientId)  
  9.             throws OAuth2Exception {  
  10.    
  11.         if (clientId.equals(id))  
  12.         {  
  13.             List<String> authorizedGrantTypes = new ArrayList<String>();  
  14.             authorizedGrantTypes.add("password");  
  15.             authorizedGrantTypes.add("refresh_token");  
  16.             authorizedGrantTypes.add("client_credentials");  
  17.    
  18.             BaseClientDetails clientDetails = new BaseClientDetails();  
  19.             clientDetails.setClientId(id);  
  20.             clientDetails.setClientSecret(secretKey);  
  21.             clientDetails.setAuthorizedGrantTypes(authorizedGrantTypes);  
  22.    
  23.             return clientDetails;  
  24.         }  
  25.         else {  
  26.             throw new NoSuchClientException("No client recognized with id: "  
  27.                     + clientId);  
  28.         }  
  29.     }  
  30.    
  31.     public String getId() {  
  32.         return id;  
  33.     }  
  34.    
  35.     public void setId(String id) {  
  36.         this.id = id;  
  37.     }  
  38.    
  39.     public String getSecretKey() {  
  40.         return secretKey;  
  41.     }  
  42.    
  43.     public void setSecretKey(String secretKey) {  
  44.         this.secretKey = secretKey;  
  45.     }  
  46.    
  47. }  

 现在基于username和passwd来验证(grant_type=password), 在<oauth:authorization-server>的拦截userAuthenticationManager中:

 

 

Java代码  收藏代码
  1. public class AAAUserAuthenticationProvider  
  2.    
  3. implements AuthenticationProvider {  
  4.    
  5.     @Autowired  
  6.     AAAProxy aaaProxy;  
  7.    
  8.     @Override  
  9.     public Authentication authenticate(Authentication authentication)  
  10.             throws AuthenticationException {  
  11.    
  12.         boolean result = aaaProxy.isValidUser(authentication.getPrincipal()  
  13.                 .toString(), authentication.getCredentials().toString());  
  14.    
  15.         if (result) {  
  16.             List<GrantedAuthority> grantedAuthorities =  
  17.    
  18. new ArrayList<GrantedAuthority>();  
  19.             AAAUserAuthenticationToken auth =  
  20.    
  21. new AAAUserAuthenticationToken(authentication.getPrincipal(),  
  22.             authentication.getCredentials(), grantedAuthorities);  
  23.    
  24.             return auth;  
  25.         } else {  
  26.             throw new BadCredentialsException("Bad User Credentials.");  
  27.         }  
  28.     }  
  29.    
  30.     public boolean supports(Class<?> arg0) {  
  31.         return true;  
  32.     }  
  33. }  

 这里的aaproxy是真正来验证user的(代理机制)不细化了,如果用户是有效,做三件事:

 

1. 在框架的security上下文中更新对象

2. TokenService将会生成一个新的token

3. TokenStore将会保存这个token

然后token就发给request的client了

最后这里是token和resource的代码:

 

Java代码  收藏代码
  1. public class AAAUserAuthenticationToken   
  2.    
  3. extends AbstractAuthenticationToken {  
  4.    
  5.     private static final long serialVersionUID = -1092219614309982278L;  
  6.     private final Object principal;  
  7.     private Object credentials;  
  8.    
  9.     public AAAUserAuthenticationToken(Object principal, Object credentials,  
  10.             Collection<? extends GrantedAuthority> authorities) {  
  11.         super(authorities);  
  12.         this.principal = principal;  
  13.         this.credentials = credentials;  
  14.         super.setAuthenticated(true);  
  15.     }  
  16.    
  17.     public Object getCredentials() {  
  18.         return this.credentials;  
  19.     }  
  20.    
  21.     public Object getPrincipal() {  
  22.         return this.principal;  
  23.     }  
  24. }  

 

Java代码  收藏代码
  1. @Path("/userresource")  
  2. public class UserResource {  
  3.    
  4.     @GET  
  5.     @Path("/userprofile")  
  6.     public String getUserProfile(){  
  7.         return "Welcome in protected Area. User enabled.";  
  8.     }  
  9. }  

 

 

测试:

使用了Fidder, 可以用curl,wget(what ever you want)

请求:

/OAuthAAA/oauth/token?username=myuser&password=mypassword
&client_id=mysupplycompany&client_secret=mycompanykey&grant_type=password



 
 

资源请求:

/OAuthAAA/protected/userresource/userprofile
Authorization: Bearer 5cf0732b-6bbb-40c7-8fab-dcfefcc2fcfe


 

 

 

补充:AAProxy的代码:

 

Java代码  收藏代码
  1. package it.iol.oauthaaa.security;  
  2.    
  3. import java.net.InetSocketAddress;  
  4. import java.net.Proxy;  
  5. import java.net.Proxy.Type;  
  6. import java.util.List;  
  7.    
  8. import org.springframework.http.HttpEntity;  
  9. import org.springframework.http.HttpHeaders;  
  10. import org.springframework.http.client.SimpleClientHttpRequestFactory;  
  11. import org.springframework.util.LinkedMultiValueMap;  
  12. import org.springframework.util.MultiValueMap;  
  13. import org.springframework.web.client.RestTemplate;  
  14.    
  15. public class AAAProxy {  
  16.    
  17.     private Proxy proxy;  
  18.     private RestTemplate template;  
  19.    
  20.     public AAAProxy() {  
  21.         proxy = new Proxy(Type.HTTP, new InetSocketAddress(  
  22.                 "proxy.abc.net"3001));  
  23.    
  24.         SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();  
  25.    
  26.         requestFactory.setProxy(proxy);  
  27.    
  28.         template = new RestTemplate(requestFactory);  
  29.     }  
  30.    
  31.     public boolean isValidUser(String user, String password) {  
  32.    
  33.         MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();  
  34.         map.add("user", user);  
  35.         map.add("password", password);  
  36.    
  37.         HttpEntity<String> response = template.postForEntity(  
  38.                 "https://authentication.local/auth", map,  
  39.                 String.class);  
  40.    
  41.         HttpHeaders headers = response.getHeaders();  
  42.    
  43.         List<String> cookies = headers.get("Set-Cookie");  
  44.    
  45.         for (String cookie : cookies) {  
  46.             if (cookie.indexOf("Auth")!=-1)  
  47.                 return true;  
  48.         }  
  49.    
  50.         return false;  
  51.     }  
  52.    
  53. }  

 

 

当grant_type="client_credentials"时的验证:



 

 

 相关资源:

https://raymondhlee.wordpress.com/2014/12/21/implementing-oauth2-with-spring-security/

https://github.com/spring-projects/spring-security-oauth/blob/master/spring-security-oauth2/src/main/java/org/springframework/security/oauth2/provider/authentication/BearerTokenExtractor.java

https://github.com/spring-projects/spring-security-oauth/tree/master/spring-security-oauth2

https://developer.linkedin.com/docs/oauth2

http://api-doc.assembla.com/content/authentication.html


原创粉丝点击