`

OAuth 2.0 客户端,第 2 部分: 客户端凭据授权

阅读更多

概述

OAuth 是一个开放的授权标准,允许客户端代表一个资源所有者获得对受保护服务器资源的访问权限。资源所有者可以是另一个客户端或最终用户。OAuth 还可以帮助最终用户将对其服务器资源的访问权限授权给第三方,而不必共享其凭据,比如用户名和密码。本系列文章遵从 RFC6749 中列出的 OAuth 2.0 授权框架。可以在 Internet Engineering Task Force 的网站上找到 RFC 6749 中列出的完整 OAuth 2.0 授权框架(请参阅 )。

授权批准

授权批准是一种凭据,可代表资源所有者用来获得访问受保护资源的访问权。客户端使用此凭据获取访问令牌,而且此访问令牌最终将与请求一起发送,以便访问受保护资源。OAuth 2.0 定义了四种授权类型:

  1. 授权码
  2. 隐式
  3. 资源所有者密码凭据
  4. 客户端凭据

这个文章系列由四个部分组成,将引导您使用上面列出的每种授权类型在 Java™ 编程中实现 OAuth 2.0 客户端。在第 2 部分中,我将解释如何实现客户端凭据授权。本文将详细介绍这种授权,并解释示例客户端代码,此代码可用于兼容 OAuth 2.0 的任何服务器接口,以便支持这种授权。在本文的最后,您应该对客户端实现有了全面的了解,并准备好下载示例客户端代码,自己进行测试。

客户端凭据授权

在此授权中,机密客户端可以只使用其客户端凭据(或其他可支持的身份验证方法,比如公钥/私钥对)从授权服务器请求一个访问令牌。假设客户端在请求访问在其自身控制下的受保护资源(客户端是资源所有者)。

图 1 中所示的流程包括以下步骤:

(A) OAuth 2.0 客户端使用其客户端凭据和授权服务器进行身份验证,并从令牌端点请求访问令牌

(B) 授权服务器对 OAuth 2.0 客户端进行身份验证,并验证客户端凭据,如果凭据是有效的,那么授权服务器将会颁发一个访问令牌。

图 1. 客户端凭据流

该图显示了在 OAuth 2.0 客户端和授权服务器之间往返的客户端凭据流

访问令牌请求

对应于 步骤 A 的访问令牌请求如 图 1 所示。

客户端对令牌端点(授权服务器)发出请求,采用 application/x-www-form-urlencoded 格式发送以下参数。

  • grant_type:必选项。该值必须设置为 "client_credentials"
  • client_id:必选项。客户端 ID。
  • client_secret:必选项。客户端密钥/密码。
  • scope:可选项。访问请求的范围

因为客户端身份验证被用作授权批准,所以不需要额外的授权。例如,客户端利用传输层安全性发出下列 HTTP 请求:

清单 1. 客户端 HTTP 请求
POST /token HTTP/1.1
Host: server.example.com
Authorization:Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials&client_id=myApp&client_secret=ab32vr

访问令牌响应

对应于 步骤 B 的访问令牌响应该如 图 1 所示。如果访问令牌请求是有效的,而且获得了授权,那么授权服务器将会返回访问令牌。成功的响应如 清单 2 所示。

清单 2. 访问令牌响应
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
  "access_token":"2YotnFZFEjr1zCsicMWpAA",
  "token_type":"example",
  "expires_in":3600,
  "example_parameter":"example_value"
}

如果请求无效,或者未经过授权,那么授权服务器将会使用代码返回一个相应的错误消息。

设置

下载部分 的 OAuth2.0_client_credentials.zip 文件中提供了示例 Outh2.0 客户端。其代码被组织为可导入 Eclipse 环境中的 Java 项目。

先决条件

您需要安装 Eclipse IDE for Java EE developers,以便设置开发环境,并导入附加项目。从 Eclipse 下载页面 下载 Eclipse。

该项目使用以下 JAR 文件:

  1. commons-codec-1.6.jar
  2. commons-logging-1.1.1.jar
  3. httpclient-4.2.5.jar
  4. httpclient-cache-4.2.5.jar
  5. httpcore-4.2.4.jar
  6. httpmime-4.2.5.jar
  7. json-simple-1.1.1.jar

第 1 至第 6 点中提到的 JAR 文件可以在 HttpComponents JAR 文件中找到。可以从 Apache HTTP Component 项目 下载它。可以从 Simple JSON 项目页面 下载 json-simple-1.1.1.jar 文件。确保已将这些 JAR 文件复制到 Java 项目的 lib文件夹中。

OAuth 2.0 客户端代码

此处讨论的 OAuth 2.0 客户端实现了客户端凭据授权。在本教程系列的后续部分中,将讨论其余授权类型,并更新客户端代码。

输入参数

使用项目的 resources 文件夹中提供的 Oauth2Client.config 属性文件向客户端提供所需的输入参数。

  • scope:这是一个可选参数。它代表访问请求的范围。由服务器返回的访问令牌只可以访问 scope 中提到的服务。
  • grant_type:需要将这个参数设置为 client_credentials,它表示客户端凭据授权。
  • client_id:注册应用程序时由资源服务器提供的客户端或使用者 ID。
  • client_secret:注册应用程序时由资源服务器提供的客户端或使用者的密码。
  • access_token:授权服务器响应有效的和经过授权的访问令牌请求时所返回的访问令牌。作为该请求的一部分,您的客户端凭据可用于交换访问令牌。
  • authentication_server_url:这表示令牌端点。批准和重新生成访问令牌的所有请求都必须发送到这个 URL。
  • resource_server_url:这表示需要联系的资源服务器的 URL,通过将授权标头中的访问令牌传递给它,访问受保护的资源。

客户端代码如 清单 3 所示。

清单 3. 客户端源代码
//Load the properties file
Properties config = OauthUtils.getClientConfigProps(OauthConstants.CONFIG_FILE_PATH);
		
//Generate the OAuthDetails bean from the config properties file
Oauth2Details oauthDetails = OauthUtils.createOauthDetails(config);
		
//Validate Input
if(!OauthUtils.isValidInput(oauthDetails)){
 System.out.println("Please provide valid config properties to continue.");
 System.exit(0);
}
		
//Determine operation
if(oauthDetails.isAccessTokenRequest()){
  //Generate new Access token
  String accessToken = OauthUtils.getAccessToken(oauthDetails);
   if(OauthUtils.isValid(accessToken)){
      System.out.println("Successfully generated Access token for
      client_credentials grant_type:"+accessToken);
   }
   else{
    System.out.println("Could not generate Access token for
    client_credentials grant_type");
   }
}
		
else {
 //Access protected resource from server using OAuth2.0
 //Response from the resource server must be in Json or Urlencoded or xml
   System.out.println("Resource endpoint url:" + oauthDetails.getResourceServerUrl());
   System.out.println("Attempting to retrieve protected resource");
   OauthUtils.getProtectedResource(oauthDetails);
}

清单 3 中的客户端代码将会读取 Oauth2Client.config 文件中提供的输入参数。它会验证 client_idclient_secret authentication_server_url 的值。如果配置文件中提供的资源服务器 URL 是有效的,那么客户端会尝试检索该 URL 中提供的受保护资源。否则,客户端只对授权服务器发出访问令牌请求,并取回访问令牌。以下部分说明了负责检索受保护资源和访问令牌的代码。

访问受保护资源

清单 4 中的代码演示了如何使用访问令牌来访问受保护的资源。

清单 4. 访问受保护的资源
String resourceURL = oauthDetails.getResourceServerUrl();
				
HttpGet get = new HttpGet(resourceURL);
get.addHeader(OAuthConstants.AUTHORIZATION,
 getAuthorizationHeaderForAccessToken(oauthDetails
  .getAccessToken()));
DefaultHttpClient client = new DefaultHttpClient();
HttpResponse response = null;
int code = -1;
	try {
	response = client.execute(get);
	code = response.getStatusLine().getStatusCode();
	if (code == 401) {
	 // Access token is invalid or expired.Regenerate the access
	 // token
	 System.out
	 .println("Access token is invalid or expired.Regenerating access 	  token....");
	 String accessToken = getAccessToken(oauthDetails);
	 if (isValid(accessToken)) {
	  // update the access token
	  // System.out.println("New access token:" + accessToken);
	   oauthDetails.setAccessToken(accessToken);
	   get.removeHeaders(OAuthConstants.AUTHORIZATION);
	   get.addHeader(OAuthConstants.AUTHORIZATION,
	   getAuthorizationHeaderForAccessToken(oauthDetails
	   .getAccessToken()));
	   get.releaseConnection();
	   response = client.execute(get);
	   code = response.getStatusLine().getStatusCode();
		if (code == 401) {
			throw new RuntimeException("Could not access protected resource.
					Server returned http 	  code:" + code);

		}

	  }
		else {
		 throw new RuntimeException(
		 Could not regenerate access token");
	       }

       }

		handleResponse(response);

注意:

  • 此方法使用从配置文件检索到的值来接受 OauthDetails bean。
  • 顾名思义,这种方法会尝试从资源服务器中检索受保护的资源。因此,我们创建一个简单的 HttpGet 方法。
  • 为了向资源服务器进行身份验证,需要将访问令牌作为 Authorization 标头的一部分发送。

    例如:Authorization:Bearer accessTokenValue

  • 创建一个 DefaultHttpClient,向资源服务器发出一个 get 请求。
  • 如果从资源服务器收到的响应代码是 401,那么用于身份验证的访问令牌可能已过期或无效。
  • 下一步是重新创建访问令牌。(请参见 清单 5。)
  • 成功地重新生成访问令牌之后,更新 OauthDetails bean 中的访问令牌值。用新的访问令牌值替换 get 方法中现有的 Authorization 标头。
  • 现在发出对受保护资源的另一个访问请求。
  • 如果访问令牌有效,而且资源服务器的 URL 也是正确的,那么您应该可以在控制台中看到响应内容。

重新生成过期的访问令牌

清单 5 中的代码将会处理已过期访问令牌的重新生成。

清单 5. 重新生成过期的访问令牌
 HttpPost post = new HttpPost(
 oauthDetails.getAuthenticationServerUrl());
 String clientId = oauthDetails.getClientId();
 String clientSecret = oauthDetails.getClientSecret();
 String scope = oauthDetails.getScope();

 List<BasicNameValuePair> parametersBody =
 new ArrayList<BasicNameValuePair>();
 parametersBody.add(new BasicNameValuePair(OAuthConstants.GRANT_TYPE,
 oauthDetails.getGrantType()));
 parametersBody.add(new BasicNameValuePair(OAuthConstants.Client_ID,
 clientId));
 parametersBody.add(new BasicNameValuePair(OAuthConstants.Client_Secret,
 clientSecret));

 
 if (isValid(scope)) {
	parametersBody.add(new BasicNameValuePair
      (OAuthConstants.SCOPE,scope));
  }

 DefaultHttpClient client = new DefaultHttpClient();
 HttpResponse response = null;
 String accessToken = null;
   try {
	post.setEntity(new UrlEncodedFormEntity(parametersBody,
       HTTP.UTF_8));
	
	response = client.execute(post);
	int code = response.getStatusLine().getStatusCode();
	if (code == 401) {
	System.out.println("Authorization
       server expects Basic authentication");
	// Add Basic Authorization header
	post.addHeader(
	OAuthConstants.AUTHORIZATION,
	getBasicAuthorizationHeader(oauthDetails.clientId,
	clientSecret));
	System.out.println("Retry with client credentials");
	post.releaseConnection();
	response = client.execute(post);
	code = response.getStatusLine().getStatusCode();
	
	if (code == 401) {
	throw new RuntimeException(
	"Could not retrieve access token for client:"
	clientId);
	   }
        }
      }
	Map<String, String> map = handleResponse(response);
	accessToken = map.get(OAuthConstants.ACCESS_TOKEN);
	} catch (ClientProtocolException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
	} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
	}

	return accessToken;

注意:

  • 这种方法生成一个 HttpPost 请求,并获得身份验证服务器的 URL。
  • Post 请求以 URL 编码参数的形式发送 client_idclient_secret,以及可选的 scope,将它们作为有效载荷的一部分。
  • 按照 OAuth 2.0 授权框架,客户端应该使用客户端凭据,或使用在发出访问令牌请求时由服务器提供的其他任何凭据设置 Authorization 标头。但是,这受制于授权服务器实现。客户端代码发出初始请求时无需添加基本身份验证标头。如果服务器返回一个未经授权的响应,那么客户端随后会试图使用客户端凭据进行身份验证。
  • OAuth 2.0 规定,应该采用 JSON 格式来发送访问令牌响应。但为了灵活性,我还添加了实用程序方法来处理来自服务器的 XML 编码或 URL 编码的响应。

测试 OAuth 2.0 客户端

本节将介绍如何建立一个 OAuth 2.0 兼容的端点,并用它来测试客户端。

用端点来测试客户端

客户端已经用 Twitter 和 OAuth 2.0 兼容的 IBM 端点(比如 IBM® Websphere® Application Server 和 IBM DataPower™)完成了成功的测试。

"在 WebSphere Application Server 中启用 OAuth 服务提供程序" 中可以找到有关在 WebSphere Application Server 上设置 OAuth 2.0 端点的说明。

运行客户端

现在,您已经设置了 OAuth 2.0 兼容的服务器,您可以测试客户端,并从服务器检索受保护的信息。

  • 将附加在本教程的 Java 项目导入到 Eclipse 工作区中。
  • 下载依赖关系 JAR 文件,并将其复制到项目的 lib 文件夹中。
  • 导航到 resources/com/ibm/oauth/Oauth2Client.config 文件并填充 client_idclient_secret  authorization_server URL 的值。
  • 在 Eclipse 中打开 Oauth2Client.java 并运行它。

访问令牌输出

您应该在控制台窗口中看到如清单 6 所示的输出。 清单 6

清单 6. 访问令牌输出
Resource server URL is null.Will assume request is for generating Access token
Validated Input

********** Response Received **********
  expires_in = 3600
  token_type = bearer
  scope =
  access_token = mc20Tn3Br8raUvCrBEap3VYMbErGXshjiXYFAwEB
Successfully generated Access token for client_credentials grant_type:
mc20Tn3Br8raUvCrBEap3VYMbErGXshjiXYFAwEB

从服务器中检索用户信息

现在,您有了访问令牌,可以向托管在 WebSphere Application Server 上的 Web 应用程序发出请求,该服务器要求使用 OAuth 2.0 进行身份验证。

  • 用访问令牌更新 Oauth2Client.confg 文件,并使用想对其进行测试的资源服务器 URL 来填充资源服务器 URL 属性。
  • 再次运行 Oauth2Client.java。

您应该在控制台窗口中看到输出,如 清单 7 所示。

清单 7. 检索用户信息
Resource endpoint url: https://localhost/protectedResource
Attempting to retrieve protected resource

********** Response Received **********
{
 "Author":"Varun Ojha",
 "Authenticatation":"Oauth2.0",
 "Result":"Success"
}

如您所见,您可以通过使用 OAuth 2.0 进行身份验证,从而成功访问 Web 应用程序。在配置文件中提供的访问令牌过期后,客户端会在下一个请求中自动重新生成访问令牌,并使用它来检索在资源服务器 URL 中提供的受保护资源。

结束语

在本教程中,您学习了 OAuth 客户端凭据的基础知识。本教程演示了如何在 Java 编程中编写一个通用的 OAuth 2.0 客户端,以便连接到 OAuth 2.0 兼容的多个端点,并从中获取受保护的资源。示例客户端被作为一个 Java 项目附加,让您能够迅速将项目导入到 Eclipse 工作区,并开始测试。在本教程系列的后续部分中,将介绍在 OAuth 2.0 授权框架中列出的其余两种授权类型。

转自http://www.ibm.com/developerworks/cn/java/se-oauthjavapt2/index.html

分享到:
评论

相关推荐

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

    OAuth 2.0 是一个授权框架,用于安全地允许第三方应用访问用户的数据,而无需共享用户的登录凭据。在Java中实现OAuth 2.0,我们可以利用Spring Security OAuth2库,它提供了服务端(Authorization Server)和客户端...

    NET Core 3.1 MVC演示Xero OAuth 2.0客户端身份验证和OAuth 2.0API

    8. **代码实现**:这个示例项目可能包含控制器、视图和模型的代码,展示如何配置OAuth 2.0客户端,如何处理授权流,以及如何使用获取的访问令牌调用Xero API。 综上所述,这个压缩包提供的项目是一个.NET Core 3.1 ...

    基于Django2.1.2的OAuth2.0授权登录

    OAuth2.0是一种开放标准,用于授权第三方应用访问用户存储在另一服务提供商(如社交媒体网站)上的私有资源,而无需共享用户的登录凭证。在Django框架中实现OAuth2.0授权登录,可以让开发者轻松地为他们的Web应用...

    oauth2.0服务端客户端代码jar包

    在Java中,客户端通常需要实现OAuth2的四个授权模式:授权码模式(Authorization Code Grant)、隐式模式(Implicit Grant)、客户端凭据模式(Client Credentials Grant)和刷新令牌模式(Refresh Token Grant)。...

    Java的oauth2.0 服务端与客户端的实现

    在Java中实现OAuth 2.0涉及到服务端(Authorization Server)和客户端(Resource Owner or Client)的角色,以及授权码(Authorization Code)、隐式(Implicit)、密码(Resource Owner Password Credentials)和...

    ssm搭建、Oauth2.0客户端和服务端

    本项目通过这三个部分的结合,实现了从简单SSM应用到OAuth2.0客户端和服务端的构建。 首先,我们来看SSM的搭建过程。Spring是核心容器,负责管理Bean;SpringMVC是Spring的Web模块,处理HTTP请求;MyBatis则是一个...

    JAVA服务端和客户端功能实现 OAuth2.0

    OAuth2.0是一种广泛使用的开放授权协议,它允许第三方应用在用户许可的情况下,访问特定的受保护资源。在Java环境中,实现OAuth2.0涉及到服务端(Authorization Server)和客户端(Resource Owner)的角色,以及授权...

    oauth2.0授权机制,授权码

    5. **扩展性**:Spring Security OAuth2.0支持多种授权类型,如密码模式、客户端凭据模式、刷新令牌模式等,可以根据实际需求灵活选择。 总的来说,OAuth2.0授权机制结合Spring Security OAuth2.0框架,为Java...

    springboot集成oauth2.0

    OAuth2.0是一个授权框架,允许第三方应用在用户授权的情况下访问其受保护的资源,而无需知道用户的原始凭证。以下是关于这个主题的详细知识点: 1. **OAuth2.0核心概念**: - **客户端(Client)**: 需要访问受...

    OAuth2.0代码模拟实现

    这个框架允许用户授权第三方应用访问他们存储在特定服务提供商(如Google或Facebook)上的数据,而无需分享他们的登录凭据。OAuth2.0的核心在于提供了一种安全的方式,使得用户可以在保持对自身账户控制的同时,让...

    oauth2.0 client

    首先,OAuth 2.0 定义了四种主要的授权类型或模式:授权码(Authorization Code)、隐式(Implicit)、密码(Resource Owner Password Credentials)和客户端凭据(Client Credentials)。 1. **授权码模式**:这是...

    Java的oauth2.0 服务端与客户端的实现.7z

    在Java环境中实现OAuth 2.0,我们可以利用Spring Security OAuth2库,这是一个广泛使用的开源库,提供了服务端和客户端的实现。 **OAuth 2.0 服务端实现(oauthserver)** 在`oauthserver`项目中,我们通常会配置...

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

    OAuth2.0 是一种授权框架,允许第三方应用在用户许可的情况下访问其受保护的资源,而无需共享用户凭证。本讲义结合代码将深入探讨如何利用Spring Security OAuth2.0 实现这一目标。 首先,OAuth2.0 有四个核心角色...

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

    OAuth2.0是授权框架的一个标准,允许第三方应用在用户授权的情况下访问其私有资源,而无需共享用户的登录凭证。这个压缩包文件"视频配套笔记_Spring Security OAuth2.0认证授权_v1.1.rar"包含了对这一主题的详细解释...

    spring oauth2.0 例子

    4. **授权类型与流**:OAuth2.0有几种授权流,如授权码流、密码流、客户端凭据流和刷新令牌流。在示例中,可能会展示如何实现其中的一种或多种。 5. **用户认证与授权**:在Spring中,通常结合Spring Security进行...

    Oauth2.0 实现代码

    OAuth 2.0 是一个授权框架,用于安全地允许第三方应用访问用户在原服务上的数据,而无需分享用户的登录凭证。在本项目中,我们关注的是如何使用 Spring Security OAuth2 来实现 OAuth 2.0 的功能。Spring Security ...

    OAuth 2.0 (Getting started with OAuth2.0)

    OAuth 2.0 是一种广泛使用的开放标准,用于授权第三方应用程序访问用户在特定服务上的数据,而无需共享用户的登录凭证。这个协议的核心在于提供了一种安全的机制,使得用户可以控制哪些应用能访问他们的资源,比如...

    oauth2.0apache服务端源码

    1. **授权流程**:OAuth 2.0 规定了授权码(Authorization Code)流、隐式(Implicit)流、客户端凭据(Client Credentials)流和密码(Resource Owner Password Credentials)流等多种授权方式。源码将包含这些流程...

Global site tag (gtag.js) - Google Analytics