`
指隙阳光12138
  • 浏览: 17979 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

【OAuth2.0】Spring Security OAuth2.0对于OAuth2.0协议中四种授权类型的实现

阅读更多
前言
OAuth2.0定义的几种Authorization Grant

 Authorization Grant是资源所有者赋予第三方client的一份证书,第三方client可以凭此证书获取一个access token,后者可以用来直接访问资源所有者的某些受限资源,而不用知道资源所有者的用户名密码等信息。

OAuth2.0中目前有四种授权类型:Authorization Code,implicit,resource owner password credentials,client credentials

 

实现
Spring的具体实现(TokenGranter)

 上述几种类型的授权类型中,Spring有对应的几种TokenGranter,类继承结构如下图:


可以看到类CompositeTokenGranter和AbstractTokenGranter直接implements接口TokenGranter。其中,

前者实际类定义中维持了一个对所有具体TokenGranter的引用list,调用其grant方法时,会遍历该list,调用每一个引用的grant方法,直到有granter生成并返回OAuth2AccessToken或者list到最后。该TokenGranter用到的地方自己看代码的过程中,发现在TokenEndpoint中有对其的直接引用,实际结合对authorization-server的配置就可以直到这个CompositeTokenGranter对其他TokenGranter的引用list怎么来的了:

 

<oauth2:authorization-server client-details-service-ref="clientDetailsService" token-services-ref="tokenServices"
                                user-approval-handler-ref="oauthUserApprovalHandler"
                                user-approval-page="oauth_approval"
                                error-page="oauth_error">
       <!--后面这几种授权方式应该都会整合进入CompositeTokenGranter的List<TokenGranter>属性当中的-->
       <oauth2:authorization-code authorization-code-services-ref="authorizationCodeServices" />
       <oauth2:implicit/>
       <oauth2:refresh-token/>
       <oauth2:client-credentials/>
       <oauth2:password/>
   </oauth2:authorization-server>
            而后者AbstractTokenGranter则是个抽象类,有具体实现的TokenGranter会继承该类

 

接口TokenGranter用于生成OAuth2AccessToken,接口就定义了一个方法:OAuth2AccessToken grant(String grantType, AuthorizationRequest authorizationRequest)。OAuth2AccessToken定义如下,其getValue()方法返回的即是返回客户端的access_token。

 

public interface OAuth2AccessToken {

	public static String BEARER_TYPE = "Bearer";

	public static String OAUTH2_TYPE = "OAuth2";

	/**
	 * The access token issued by the authorization server. This value is REQUIRED.
	 */
	public static String ACCESS_TOKEN = "access_token";

	/**
	 * The type of the token issued as described in <a
	 * href="http://tools.ietf.org/html/draft-ietf-oauth-v2-22#section-7.1">Section 7.1</a>. Value is case insensitive.
	 * This value is REQUIRED.
	 */
	public static String TOKEN_TYPE = "token_type";

	/**
	 * The lifetime in seconds of the access token. For example, the value "3600" denotes that the access token will
	 * expire in one hour from the time the response was generated. This value is OPTIONAL.
	 */
	public static String EXPIRES_IN = "expires_in";

	/**
	 * The refresh token which can be used to obtain new access tokens using the same authorization grant as described
	 * in <a href="http://tools.ietf.org/html/draft-ietf-oauth-v2-22#section-6">Section 6</a>. This value is OPTIONAL.
	 */
	public static String REFRESH_TOKEN = "refresh_token";

	/**
	 * The scope of the access token as described by <a
	 * href="http://tools.ietf.org/html/draft-ietf-oauth-v2-22#section-3.3">Section 3.3</a>
	 */
	public static String SCOPE = "scope";

	/**
	 * The additionalInformation map is used by the token serializers to export any fields used by extensions of OAuth.
	 * @return a map from the field name in the serialized token to the value to be exported. The default serializers 
	 * make use of Jackson's automatic JSON mapping for Java objects (for the Token Endpoint flows) or implicitly call 
	 * .toString() on the "value" object (for the implicit flow) as part of the serialization process.
	 */
	Map<String, Object> getAdditionalInformation();

	Set<String> getScope();

	OAuth2RefreshToken getRefreshToken();

	String getTokenType();

	boolean isExpired();

	Date getExpiration();

	int getExpiresIn();

	String getValue();

}
  • AuthorizationCodeTokenGranter

我们的项目使用的授权类型是Authorization Code,其余授权类型暂时完全没看的状态。

结合上面说的,第三方client会先申请authorization code(这部分逻辑以后单独说),得到code之后,由第三方client向/auth/token发起获取access token请求(调用的实际就是TokenEndpoint中的逻辑),类似:http://localhost:8080/oauth/token?client_id=id&client_secret=secret&grant_type=authorization_code&scope=read,write&redirect_uri=none&code=3iW8lA

 

@RequestMapping(value = "/oauth/token")
public class TokenEndpoint extends AbstractEndpoint {

	@RequestMapping
	public ResponseEntity<OAuth2AccessToken> getAccessToken(Principal principal,
			@RequestParam(value = "grant_type", required = false) String grantType,
			@RequestParam Map<String, String> parameters) {

		//...
                //...
                //部分代码省略 getTokenGranter()返回的是CompositeTokenGranter对象
		OAuth2AccessToken token = getTokenGranter().grant(grantType, authorizationRequest);
		if (token == null) {
			throw new UnsupportedGrantTypeException("Unsupported grant type: " + grantType);
		}

		return getResponse(token);

	}
}
 

 

而CompositeTokenGranter的实现如下:

 

public class CompositeTokenGranter implements TokenGranter {

	private final List<TokenGranter> tokenGranters;

	public CompositeTokenGranter(List<TokenGranter> tokenGranters) {
		this.tokenGranters = new ArrayList<TokenGranter>(tokenGranters);
	}
	
	public OAuth2AccessToken grant(String grantType, AuthorizationRequest authorizationRequest) {
		for (TokenGranter granter : tokenGranters) {
			OAuth2AccessToken grant = granter.grant(grantType, authorizationRequest);
			if (grant!=null) {
				return grant;
			}
		}
		return null;
	}

}
 

 

所以,这样,如果我们上面的xml配置中,启用了AuthorizaitonCode授权方式,那么这里就会使用到,并调用其grant方法获取access token(grant方法实际是AbstractTokenGranter类中定义好的,子类只需要定义好其需要的几个方法即可,比如getOAuth2Authentication())

in class AbstractTokenGranter:

 

	public OAuth2AccessToken grant(String grantType, AuthorizationRequest authorizationRequest) {

		if (!this.grantType.equals(grantType)) {
			return null;
		}
		
		String clientId = authorizationRequest.getClientId();
		ClientDetails client = clientDetailsService.loadClientByClientId(clientId);
		validateGrantType(grantType, client);
		
		logger.debug("Getting access token for: " + clientId);
		return getAccessToken(authorizationRequest);

	}

	protected OAuth2AccessToken getAccessToken(AuthorizationRequest authorizationRequest) {
		DefaultAuthorizationRequest outgoingRequest  = new DefaultAuthorizationRequest(authorizationRequest);
		outgoingRequest.setApproved(true);
		// FIXME: do we need to explicitly set approved flag here?
		return tokenServices.createAccessToken(getOAuth2Authentication(outgoingRequest));
	}
 in subclass AuthorizationCodeTokenGranter(会对client id和redirect uri等进行校验,并且要注意的是,因为是使用code换取access token,所以这里还需要另用掉的code失效):

 

 

	@Override
	protected OAuth2Authentication getOAuth2Authentication(AuthorizationRequest authorizationRequest) {

		Map<String, String> parameters = authorizationRequest.getAuthorizationParameters();
		String authorizationCode = parameters.get("code");
		String redirectUri = parameters.get(AuthorizationRequest.REDIRECT_URI);

		if (authorizationCode == null) {
			throw new OAuth2Exception("An authorization code must be supplied.");
		}

		AuthorizationRequestHolder storedAuth = authorizationCodeServices.consumeAuthorizationCode(authorizationCode);//让code失效,如果使用DB的话,就是删除该code对应的记录,这里DB删除之后会把这条记录同时返回
		if (storedAuth == null) {
			throw new InvalidGrantException("Invalid authorization code: " + authorizationCode);
		}

		AuthorizationRequest pendingAuthorizationRequest = storedAuth.getAuthenticationRequest();//反序列化,client申请code时是将code及其对应的AuthorizationRequest对象序列化之后一并存入Db的,所以这里可以反序列化出来使用
		// https://jira.springsource.org/browse/SECOAUTH-333
		// This might be null, if the authorization was done without the redirect_uri parameter
		String redirectUriApprovalParameter = pendingAuthorizationRequest.getAuthorizationParameters().get(
				AuthorizationRequest.REDIRECT_URI);

		if ((redirectUri != null || redirectUriApprovalParameter != null)
				&& !pendingAuthorizationRequest.getRedirectUri().equals(redirectUri)) {
			throw new RedirectMismatchException("Redirect URI mismatch.");
		}

		String pendingClientId = pendingAuthorizationRequest.getClientId();
		String clientId = authorizationRequest.getClientId();
		if (clientId != null && !clientId.equals(pendingClientId)) {
			// just a sanity check.
			throw new InvalidClientException("Client ID mismatch");
		}

		// Secret is not required in the authorization request, so it won't be available
		// in the pendingAuthorizationRequest. We do want to check that a secret is provided
		// in the token request, but that happens elsewhere.

		Map<String, String> combinedParameters = new HashMap<String, String>(storedAuth.getAuthenticationRequest()
				.getAuthorizationParameters());
		// Combine the parameters adding the new ones last so they override if there are any clashes
		combinedParameters.putAll(parameters);
		// Similarly scopes are not required in the token request, so we don't make a comparison here, just
		// enforce validity through the AuthorizationRequestFactory.
		DefaultAuthorizationRequest outgoingRequest = new DefaultAuthorizationRequest(pendingAuthorizationRequest);
		outgoingRequest.setAuthorizationParameters(combinedParameters);

		Authentication userAuth = storedAuth.getUserAuthentication();
		return new OAuth2Authentication(outgoingRequest, userAuth);

	}
 
之后剩余的就是生成token的流程了。源码里面都写的很清晰。
自己记住的就几点:
  1. token的value是一个UUID值,而存储进入DB的是对这个UUID值处理之后的值(类似MD5),所以想直接根据返回给client的value直接查询DB是有点麻烦的==,=
  2. 貌似authorization id也是类似的生成逻辑....
  3. 在现在项目oauth相关的表存储中,很多都用到了序列化将整个对象存储为blob类型的字段,还涉及到反序列化
  4. 单步调试的过程中,发现,一次申请access token的请求中,多次调用了根据clientId查询DB的情况,所以在实际使用中,考虑使用缓存。目前我们自己对查询client和查询user信息加了缓存,token的缓存略麻烦,暂时没加。

 

  •  其他待续...

 

  • 大小: 161.8 KB
分享到:
评论

相关推荐

    spring security + oauth 2.0 实现单点登录、认证授权

    Spring Security和OAuth 2.0是两个在Web应用安全领域广泛应用的框架,它们结合使用可以构建强大的单点登录(SSO)和认证授权系统。在这个系统中,`xp-sso-server`代表了认证服务器,而`xp-sso-client-a`和`xp-sso-...

    spring security oauth2.0 (讲义+代码)

    本讲义结合代码将深入探讨如何利用Spring Security OAuth2.0 实现这一目标。 首先,OAuth2.0 有四个核心角色:资源所有者(Resource Owner)、客户端(Client)、资源服务器(Resource Server)和授权服务器...

    Spring Security OAuth2.0学习笔记.zip

    Spring Security OAuth2.0学习笔记 ...OAuth2.0认证的四种模式?它们的大体流程是什么? Spring cloud Security OAuth2包括哪些组件?职责? 分布式系统认证需要解决的问题? 掌握学习方法,掌握思考方式。

    视频配套笔记_Spring Security OAuth2.0认证授权_v1.1.rar

    在Spring Security OAuth2.0的配置中,开发者需要定义这些组件的行为,例如设置授权类型、定义客户端信息、配置资源服务器等。同时,还需要处理各种授权流,如授权码流、密码流、客户端凭据流等,每种流都有其特定的...

    Spring Security Oauth2.0认证授权专题

    Spring boot+Spring Security Oauth2.0,Sprint cloud+Spring Security Oauth2集成。四种认证方式。附带有代码,和案例,案例,还有视频链接。我保证看完就回,如果视频链接失效,评论回复我,我单独再给你一份。

    完整Oauth 2.0实现实例

    - 使用 Spring Security OAuth2 框架,它可以简化 OAuth 2.0 的实现。首先,你需要在项目中引入相关依赖。 - 配置授权服务器,定义客户端详情,包括客户端ID、客户端秘密、授权类型等。 - 创建数据库表,用于存储...

    微信oauth2.0授权

    微信OAuth2.0授权是一种广泛应用于移动应用和网站的第三方登录解决方案,主要目的是为了安全地获取用户的微信身份标识——openid,以便提供个性化服务或者与其他微信功能集成。在本文中,我们将详细探讨微信OAuth2.0...

    spring security 基于oauth 2.0 实现 sso 单点登录Demo.zip

    spring security 基于oauth 2.0 实现 sso 单点登录Demo 使用 spring security 基于oauth 2.0 实现 sso 单点登录Demo spring boot + spring security + spring security oauth

    Spring Security OAuth 2.0

    Spring Security OAuth 2.0 是一种基于 OAuth 2.0 协议的身份验证和授权框架,它提供了一个灵活和可扩展的解决方案来保护基于 Web 的应用程序。OAuth 2.0 是一种行业标准的授权协议,提供了多种授权模式来满足不同的...

    spring security oauth2.0 需要的基础 sql 文件

    spring security oauth2.0 需要的基础 sql 文件

    OAuth2.0代码模拟实现

    在这个OAuth2.0实现中,它将定义项目依赖,如Spring Security OAuth2库,用于处理OAuth2.0协议的各个步骤。可能的依赖包括`spring-security-oauth2`, `spring-web`, `spring-security-core`, `spring-security-...

    spring oauth2.0 例子

    这个"spring oauth2.0 例子"是一个在MyEclipse集成开发环境中创建的示例项目,用于演示如何在Spring框架中实现OAuth2.0认证和授权流程。 首先,OAuth2.0的核心概念包括客户端、资源所有者(用户)、授权服务器和...

    Java的oauth2.0 服务端与客户端的实现(源码)

    在Java中实现OAuth 2.0,我们可以利用Spring Security OAuth2库,它提供了服务端(Authorization Server)和客户端(Resource Server)的支持。在提供的压缩包中,包含两个Maven项目,一个是`oauthserver`,代表了...

    oauth2.0授权机制,授权码

    1. **授权码模式**:这是OAuth2.0中最常见的授权类型,适用于有服务器端的应用。当用户同意授权后,授权服务器会返回一个授权码给客户端。客户端随后使用这个授权码向授权服务器验证并换取访问令牌(Access Token)...

    oauth2.0协议授权

    OAuth2.0主要有四种授权类型:授权码(Authorization Code)、隐式(Implicit)、密码(Resource Owner Password Credentials)和客户端凭证(Client Credentials)。这里主要讨论最常用的授权码流程: 1. 用户在...

    Spring Cloud Alibaba 集成 Spring Security OAuth2.0 实现认证和授权

    分布式系统的认证和授权 分布式架构采用 Spring Cloud Alibaba 认证和授权采用 Spring Security OAuth2.0 实现方法级权限控制 网关采用 gateway 中间件 服务注册和发现采用 nacos

    spring cloud + vue + oAuth2.0全家桶实战

    在本项目中,通过集成Spring Security OAuth2,我们可以实现用户的认证和授权流程。用户可以通过微信等第三方账号登录,简化注册和登录步骤,提升用户体验。同时,OAuth2.0的令牌(Token)机制确保了数据传输的安全...

    springboot集成oauth2.0

    在"spring-security-oauth2-example-master"这个项目中,你可以找到一个完整的SpringBoot集成OAuth2.0的示例,包括配置、控制器、服务以及客户端的实现,通过学习和研究该项目,可以更好地理解上述知识点,并实际...

    Spring Security OAuth2.0

    Spring Security OAuth2.0 提供了实现OAuth2.0规范的组件,与Spring Security整合,为开发人员提供了便捷的方式来实现安全认证和授权。 **1. OAuth2.0 架构组件** OAuth2.0 主要包含四个角色:资源所有者(Resource...

    Spring Security oAuth2.0 Demo.zip

    Spring Security框架 oAuth2.0协议标准,实现认证服务器和资源服务器,并实现oAuth2.0自定义登陆和授权界面,Access_token和Refresh_token过期时间的设置,以及数据库表结构建表语句,参考博客能更好的学习和了解,...

Global site tag (gtag.js) - Google Analytics