spring-oauth2原理及使用
来源:互联网 发布:网络集成版驱动精灵 编辑:程序博客网 时间:2024/06/07 18:26
spring-oauth2原理及使用
spring-oauth2 (bearer)是基于spring-security的验证机制,对于第三方访问受限资源时通过token机制来验证
验证steps:
通过时序图来看一下,验证方式:
发送username, password, client_id, client_secret, grant_type到server
server返回包括access_token, token_type, refresh_token, expires_in
其中,expires_in有效期,如果超期了,refresh_token起作用,如下:
使用refresh_token重新发起验证请求
来看一下,如何通过spring配置,完成上面的验证机制:
- <?xml version="1.0" encoding="UTF-8" ?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:oauth="http://www.springframework.org/schema/security/oauth2"
- xmlns:sec="http://www.springframework.org/schema/security" xmlns:mvc="http://www.springframework.org/schema/mvc"
- xmlns:context="http://www.springframework.org/schema/context"
- xsi:schemaLocation="http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2-1.0.xsd
- http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
- http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd
- http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
- http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
- <sec:http pattern="/oauth/token" create-session="stateless"
- authentication-manager-ref="authenticationManager">
- <sec:intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY" />
- <sec:anonymous enabled="false" />
- <sec:http-basic entry-point-ref="clientAuthenticationEntryPoint" />
- <sec:custom-filter ref="clientCredentialsTokenEndpointFilter" before="BASIC_AUTH_FILTER" />
- <sec:access-denied-handler ref="oauthAccessDeniedHandler" />
- </sec:http>
- <sec:http pattern="/protected/**" create-session="never"
- entry-point-ref="oauthAuthenticationEntryPoint">
- <sec:anonymous enabled="false" />
- <sec:intercept-url pattern="/protected/**" method="GET" access="IS_AUTHENTICATED_FULLY" />
- <sec:custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
- <sec:access-denied-handler ref="oauthAccessDeniedHandler" />
- </sec:http>
- <bean id="oauthAuthenticationEntryPoint"
- class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
- </bean>
- <bean id="clientAuthenticationEntryPoint"
- class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
- <property name="realmName" value="springsec/client" />
- <property name="typeName" value="Basic" />
- </bean>
- <bean id="oauthAccessDeniedHandler"
- class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler">
- </bean>
- <bean id="clientCredentialsTokenEndpointFilter"
- class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
- <property name="authenticationManager" ref="authenticationManager" />
- </bean>
- <sec:authentication-manager alias="authenticationManager">
- <sec:authentication-provider user-service-ref="clientDetailsUserService" />
- </sec:authentication-manager>
- <bean id="clientDetailsUserService"
- class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
- <constructor-arg ref="clientDetails" />
- </bean>
- <bean id="clientDetails" class="it.iol.oauthaaa.security.AAAGuestServiceImpl">
- <property name="id" value="mysupplycompany" />
- <property name="secretKey" value="mycompanykey" />
- </bean>
- <sec:authentication-manager id="userAuthenticationManager">
- <sec:authentication-provider ref="customUserAuthenticationProvider" />
- </sec:authentication-manager>
- <bean id="customUserAuthenticationProvider"
- class="it.iol.oauthaaa.security.AAAUserAuthenticationProvider">
- </bean>
- <oauth:authorization-server
- client-details-service-ref="clientDetails" token-services-ref="tokenServices">
- <oauth:authorization-code />
- <oauth:implicit/>
- <oauth:refresh-token/>
- <oauth:client-credentials />
- <oauth:password authentication-manager-ref="userAuthenticationManager"/>
- </oauth:authorization-server>
- <oauth:resource-server id="resourceServerFilter"
- resource-id="springsec" token-services-ref="tokenServices" />
- <bean id="tokenStore"
- class="org.springframework.security.oauth2.provider.token.InMemoryTokenStore" />
- <bean id="tokenServices"
- class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
- <property name="tokenStore" ref="tokenStore" />
- <property name="supportRefreshToken" value="true" />
- <property name="accessTokenValiditySeconds" value="120"></property>
- <property name="clientDetailsService" ref="clientDetails" />
- </bean>
- <mvc:annotation-driven />
- <mvc:default-servlet-handler />
- <context:annotation-config/>
- <bean id="MyResource" class="it.iol.oauthaaa.resources.UserResource"></bean>
- <bean id="aaaProxy" class="it.iol.oauthaaa.security.AAAProxy"></bean
- </beans>
通过发起/oauth/token 请求, filter拦截处理,具体代码:
- @Service
- public class AAAGuestServiceImpl implements ClientDetailsService {
- private String id;
- private String secretKey;
- @Override
- public ClientDetails loadClientByClientId(String clientId)
- throws OAuth2Exception {
- if (clientId.equals(id))
- {
- List<String> authorizedGrantTypes = new ArrayList<String>();
- authorizedGrantTypes.add("password");
- authorizedGrantTypes.add("refresh_token");
- authorizedGrantTypes.add("client_credentials");
- BaseClientDetails clientDetails = new BaseClientDetails();
- clientDetails.setClientId(id);
- clientDetails.setClientSecret(secretKey);
- clientDetails.setAuthorizedGrantTypes(authorizedGrantTypes);
- return clientDetails;
- }
- else {
- throw new NoSuchClientException("No client recognized with id: "
- + clientId);
- }
- }
- public String getId() {
- return id;
- }
- public void setId(String id) {
- this.id = id;
- }
- public String getSecretKey() {
- return secretKey;
- }
- public void setSecretKey(String secretKey) {
- this.secretKey = secretKey;
- }
- }
现在基于username和passwd来验证(grant_type=password), 在<oauth:authorization-server>的拦截userAuthenticationManager中:
- public class AAAUserAuthenticationProvider
- implements AuthenticationProvider {
- @Autowired
- AAAProxy aaaProxy;
- @Override
- public Authentication authenticate(Authentication authentication)
- throws AuthenticationException {
- boolean result = aaaProxy.isValidUser(authentication.getPrincipal()
- .toString(), authentication.getCredentials().toString());
- if (result) {
- List<GrantedAuthority> grantedAuthorities =
- new ArrayList<GrantedAuthority>();
- AAAUserAuthenticationToken auth =
- new AAAUserAuthenticationToken(authentication.getPrincipal(),
- authentication.getCredentials(), grantedAuthorities);
- return auth;
- } else {
- throw new BadCredentialsException("Bad User Credentials.");
- }
- }
- public boolean supports(Class<?> arg0) {
- return true;
- }
- }
这里的aaproxy是真正来验证user的(代理机制)不细化了,如果用户是有效,做三件事:
1. 在框架的security上下文中更新对象
2. TokenService将会生成一个新的token
3. TokenStore将会保存这个token
然后token就发给request的client了
最后这里是token和resource的代码:
- public class AAAUserAuthenticationToken
- extends AbstractAuthenticationToken {
- private static final long serialVersionUID = -1092219614309982278L;
- private final Object principal;
- private Object credentials;
- public AAAUserAuthenticationToken(Object principal, Object credentials,
- Collection<? extends GrantedAuthority> authorities) {
- super(authorities);
- this.principal = principal;
- this.credentials = credentials;
- super.setAuthenticated(true);
- }
- public Object getCredentials() {
- return this.credentials;
- }
- public Object getPrincipal() {
- return this.principal;
- }
- }
- @Path("/userresource")
- public class UserResource {
- @GET
- @Path("/userprofile")
- public String getUserProfile(){
- return "Welcome in protected Area. User enabled.";
- }
- }
测试:
使用了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的代码:
- package it.iol.oauthaaa.security;
- import java.net.InetSocketAddress;
- import java.net.Proxy;
- import java.net.Proxy.Type;
- import java.util.List;
- import org.springframework.http.HttpEntity;
- import org.springframework.http.HttpHeaders;
- import org.springframework.http.client.SimpleClientHttpRequestFactory;
- import org.springframework.util.LinkedMultiValueMap;
- import org.springframework.util.MultiValueMap;
- import org.springframework.web.client.RestTemplate;
- public class AAAProxy {
- private Proxy proxy;
- private RestTemplate template;
- public AAAProxy() {
- proxy = new Proxy(Type.HTTP, new InetSocketAddress(
- "proxy.abc.net", 3001));
- SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
- requestFactory.setProxy(proxy);
- template = new RestTemplate(requestFactory);
- }
- public boolean isValidUser(String user, String password) {
- MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
- map.add("user", user);
- map.add("password", password);
- HttpEntity<String> response = template.postForEntity(
- "https://authentication.local/auth", map,
- String.class);
- HttpHeaders headers = response.getHeaders();
- List<String> cookies = headers.get("Set-Cookie");
- for (String cookie : cookies) {
- if (cookie.indexOf("Auth")!=-1)
- return true;
- }
- return false;
- }
- }
当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
- spring-oauth2原理及使用
- spring aop原理及使用
- Spring @Transactional原理及使用
- Spring @Transactional原理及使用
- Secure Spring REST API使用OAuth2
- 使用Spring boot 快速 搭建 OAuth2 Server
- Spring Security OAuth2实现使用JWT
- 使用Spring security oauth2遇到的问题
- Oauth2.0详解及安全使用
- 【JavaEE】SSH+Spring Security+Spring oauth2环境方法及example
- 【JavaEE】SSH+Spring Security+Spring oauth2环境方法及example
- 【JavaEE】SSH+Spring Security+Spring oauth2整合及example
- OAuth2 & Spring Security OAuth2 总结
- spring mvc DelegatingFilterProxy的原理及使用
- spring @RequestBody @ResponseBody使用及原理
- Spring @Transactional的使用及原理
- spring-session简介、使用及实现原理
- Spring Cloud原理分析及使用<一>
- 0804Java 变量、包的定义
- mysql+mmm+proxy实现mysql读写分离及HA
- 1182: 查询记录(结构体专题)
- 最短路径问题
- 17个css知识点整理【下】
- spring-oauth2原理及使用
- Spark转换(transform)与动作(action)一览
- MySQL数据类型
- 开屏广告出了问题的处理和部分产品计划
- JS
- CSS布局整理
- Python正则表达式操作指南
- MySQL简单查询语句
- 图片弹出预览js