OAuth是一种开放的授权标准,可让客户端代表资源所有者访问受保护的服务器资源。 资源所有者可以是其他客户端或最终用户。 OAuth还可以帮助最终用户授权第三方访问其服务器资源,而无需共享其凭据(例如用户名和密码)。 本系列文章遵循RFC6749中概述的OAuth 2.0授权框架。 可以在Internet工程任务组网站上找到RFC 6749中概述的完整OAuth 2.0授权框架。

授权补助

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

  1. 授权码
  2. 隐含的
  3. 资源所有者密码凭证
  4. 客户凭证

本系列文章将指导您使用上面列出的每种授予类型,在Java™编程中实现OAuth 2.0客户端。 在第三部分中,我将解释如何实现授权码授予。 本文将详细说明该赠款,并说明可用于与支持此赠款的任何OAuth 2.0兼容服务器进行交互的示例客户端代码。 到本文结尾,您应该对客户端实现有完整的了解,并准备下载示例客户端代码以进行自己的测试。

授权码授予

该授权针对机密客户端进行了优化,用于获取访问令牌和刷新令牌。 这是基于重定向的流程,因此,客户端必须能够与资源所有者的用户代理(通常是Web浏览器)进行交互,并且还必须能够(通过重定向)接受来自授权服务器的传入请求。

授权代码授予如图1所示。

图1.授权代码流程

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

  • (A)客户端(通常是Web应用程序)通过将资源所有者的用户代理(通常是Web浏览器)定向到授权端点来启动流程。 客户端的请求包括客户端标识符,请求的范围,本地状态和重定向URI。 授权访问(或拒绝访问)后,授权服务器将用户代理(通常是Web浏览器)定向回重定向URI。
  • (B)资源所有者通过用户代理向授权服务器进行身份验证,并授予或拒绝客户端的访问请求。
  • (C)如果资源所有者授予访问权限,则授权服务器使用之前(在请求中或在客户端注册期间)提供的重定向URI将用户代理(通常是Web浏览器)重定向回客户端。 重定向URI包括授权码和客户端之前提供的任何本地状态。
  • (D)客户端通过包括上一步中收到的授权代码,从授权服务器的令牌端点发出访问令牌请求。 发出请求时,客户端使用客户端凭据向授权服务器进行身份验证。 客户端还包括用于获得授权码以进行验证的重定向URI。
  • (E)授权服务器对客户端进行身份验证。 它验证授权码,并确保接收到的重定向URI与步骤(C)中用于重定向客户端的URI匹配。 如果有效,授权服务器将以访问令牌和(可选)刷新令牌进行响应,以防请求离线访问。

授权码请求

授权代码请求对应于图1中描述的步骤(A)和(B)。在步骤(A)中,客户端以application/x-www-form-urlencoded格式向授权服务器发出请求。在清单1中。

清单1.授权代码请求的示例
GET /authorize?response_type=code&client_id=s6BhdRkqt3&state=xyz
&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1
Host: server.example.com

该请求必须包含以下参数:

  • response_type :必需。 该值必须设置为code
  • client_id :必填。 客户端ID。
  • redirect_uri :必需。 用于用户代理重定向。
  • scope :可选。 访问请求的范围。
  • state :可选。 维持请求和回调之间的状态。

在授权服务器验证了请求之后,服务器将HTTP重定向代码302响应发送回客户端。 该响应还将在http Location标头中包含重定向URI。 在步骤(B)中,客户端必须将用户代理(通常是Web浏览器)重定向到此URI。 此重定向URI通常是一个登录页面,资源所有者可以在其中使用其凭据登录并授予/撤消对客户端请求的访问权限。

授权码回应

授权代码响应如图1的步骤(C)所示。如果资源所有者批准了访问请求,则授权服务器将发布授权代码。 授权服务器将用户代理重定向到步骤(A)中作为请求的一部分提供的重定向URI,并使用application/x-www-form-urlencoded将授权代码包括为重定向URI的查询组件的一部分。格式。

URI参数如下:

  • Code :必填。 授权服务器生成的授权代码。 该代码是临时代码,必须在生成后立即过期。 客户端不得多次使用授权码。 授权服务器应撤消使用相同代码的其他任何请求。 授权代码绑定到客户端标识符和重定向URI。
  • State :必填。 如果客户端的授权代码请求中存在state参数,则必须将此参数设置为从客户端收到的确切值。

访问令牌请求

这对应于图1中的步骤(D)。客户端使用application/x-www-form-urlencoded格式向令牌端点(授权服务器)发出请求,如清单2所示。

清单2.访问令牌请求的示例
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencodedgrant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom&client_id=c342

访问令牌请求必须设置以下参数:

  • grant_type :必需。 该值必须设置为authorization_code
  • client_id :必填。 客户端ID。
  • client_secret :可选。 秘密。 与授权服务器进行身份验证。
  • code :必填。 从服务器收到的授权码。
  • redirect_uri :必需。 与步骤(A)中发送的相同。

授权服务器验证代码和重定向URI是否有效。 对于机密客户端,授权服务器还使用在请求正文或授权标头中传递的客户端凭据对客户端进行身份验证。

访问令牌响应

这对应于图1中的步骤(E)。如果访问令牌请求有效且被授权,则授权服务器在访问令牌响应中返回访问令牌。 清单3显示了成功响应的示例。

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

如果请求无效或未授权,则授权服务器返回带有代码的适当错误消息。

刷新访问令牌请求

这是一个可选步骤,如果客户端请求脱机访问并作为访问令牌请求的一部分提供了refresh_token ,则此步骤适用。 访问令牌是临时的,通常在一个小时后过期。 访问令牌过期后,客户端将需要重复身份验证过程,而资源所有者将需要登录并提供授权,以使客户端能够再次提出访问令牌请求。

如果客户端需要刷新访问令牌,而浏览器中不存在资源所有者登录并进行身份验证,则客户端将使用脱机访问。 客户端可以在发出第一个授权码请求时请求脱机访问(请参阅步骤(A))。 在这种方案下,授权服务器除访问令牌外还返回刷新令牌。 刷新令牌是一个长期有效的令牌,除非资源所有者明确将其吊销,否则它不会过期。 每次访问令牌到期时,客户端都可以使用刷新令牌重新生成访问令牌,而资源所有者无需登录并授权访问请求。

客户端使用application/x-www-form-urlencoded格式向令牌端点(授权服务器)发出请求,如清单4所示:

清单4.对令牌端点的请求
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencodedgrant_type=refresh_token&refresh_token=tGzv3JOkF0XG5Qx2TlKWIA

请求参数定义如下:

  • grant_type :必需。 该值必须设置为refresh_token
  • refresh_token :必需。 这是从访问令牌请求中较早检索到的。
  • scope :可选。 访问请求的范围。

授权服务器验证刷新令牌并颁发新的访问令牌。

刷新访问令牌响应

如果请求成功,授权服务器将返回一个新的访问令牌。 清单5显示了成功响应的示例。

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

如果请求无效或未授权,则授权服务器返回带有代码的适当错误消息。

建立

示例Outh2.0客户端是一个动态Web项目。 您可以从Downloads下载包含项目和源代码的.war文件。 您将.war文件导入到Eclipse环境中。

先决条件

您需要Java EE开发人员的Eclipse IDE来设置开发环境并导入附加的项目。 您可以从Eclipse下载页面下载Eclipse。

您需要Apache Tomcat JSP / Servlet容器来运行OAuth 2.0 Web客户端。 您可以从Apache Tomcat下载页面下载Tomcat。

依存关系

客户端代码项目取决于以下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

可以在HttpComponents JAR文件中找到第1至6点中提到的JAR文件,可以从HttpComponents Downloads下载页面下载该文件 。 可以从JSON Simple项目下载json-simple-1.1.1.jar文件。 确保将这些jar复制到Apache Tomcat安装目录的lib文件夹中。 默认情况下,某些必需的JAR文件在Tomcat中可能已经可用,因此您只需要复制丢失的文件。

将项目.war文件导入Eclipse

安装了Eclipse和Apache Tomcat之后,需要从“ 下载”部分导入.war文件。 要导入war文件,请遵循Eclipse网站“ 导入Web归档(WAR)文件 ”中概述的这些简单步骤。

将.war文件导入Eclipse时,请确保将Tomcat服务器与项目关联。 您需要选择Tomcat版本并提供Tomcat安装根目录的路径才能完成配置。

您可以在“ 创建Tomcat服务器 ”中获得有关如何将Tomcat服务器与项目关联的更多详细说明。

将.war文件成功导入到Eclipse工作区之后,您将在项目层次结构的Java Resources / src下找到源代码。

运行OAuth 2.0客户端

成功导入.war文件并使用必需的JAR文件设置Tomcat之后,可以通过右键单击项目名称OAuth2.0_AuthCode并选择Run AsRun on Server运行客户端。

这会将客户端部署到服务器上,并在Eclipse的内部浏览器中加载index.html页面。 就个人而言,我更喜欢在外部浏览器上与Web客户端进行交互。

您可以通过以下任意浏览器访问Web客户端: http://localhost:8080/OAuth2.0_AuthCode

接下来的部分将详细介绍客户端代码,并向您展示如何使用流行的OAuth 2.0兼容服务器(例如Salesforce,Google和IBM)测试该客户端。

OAuth 2.0客户端代码

本文中的示例OAuth 2.0客户端实现了授权代码授予。 样例客户端代码是一个Web应用程序,而不是一个常规的Java项目,在前面的文章中讨论了授予类型的情况。 这是因为授权码授予流程旨在迎合Web应用程序,并且针对通常是Web浏览器的用户代理进行了优化。

输入参数

需要使用项目中src文件夹下的Oauth2Client.config属性文件提供客户端的输入参数。 输入参数为:

  • scope :这是一个可选参数。 它表示访问请求的范围。 服务器返回的访问令牌只能访问范围中提到的那些服务。
  • state :这是一个可选参数。 它用于维护客户端请求和来自授权服务器的重定向响应之间的状态,以确保客户端的完整性。
  • grant_type :这需要被设置为authorization_code表示授权代码授权类型。
  • client_id :当您向资源服务器注册应用程序时,资源服务器提供的客户端或使用者ID。
  • client_secret :资源服务器向您注册应用程序时提供的客户端或使用者密码。
  • access_token :令牌端点响应有效和授权的访问令牌请求而返回的访问令牌。 授权服务器返回的授权代码被交换为访问令牌。
  • refresh_token :令牌端点响应于有效和授权的访问令牌请求而返回的刷新令牌。 刷新令牌可用于刷新过期的访问令牌,而无需再次出现资源所有者进行身份验证。 客户端需要从服务器显式请求刷新令牌。
  • redirect_uri :授权服务器将用户代理重定向到的URI,作为授权代码请求的一部分。 授权代码发送到此URI。
  • authentication_server_url :这代表授权服务器。 所有获取授权码的请求都必须发送到该URL。
  • token_endpoint_url :这表示令牌端点。 需要将所有用于获取访问令牌和通过刷新令牌请求刷新访问令牌的请求发送到此URL。
  • resource_server_url :这表示通过将授权标头中的访问令牌传递给受保护资源来访问该资源服务器所需要的URL。
  • approval_prompt_key :授权服务器用来定义批准提示条件的属性名称。 通常,每个授权服务器(Salesforce,Google,IBM等)都具有一个自定义属性,该属性需要作为授权代码请求的一部分传入,以表明客户端是否要针对每个请求强制执行批准提示。 Google的属性名称为approval_prompt 。 对于Salesforce,这是login consent
  • access_type_key :授权服务器用来定义访问类型条件的属性名称。 通常,每个授权服务器(Salesforce,Google,IBM等)都有一个自定义方法,客户端可以通过该方法传达其希望与访问令牌一起发布刷新令牌的信息,作为访问令牌请求的一部分。 Google通过提供access_type属性来实现。 Salesforce要求您输入值refresh_token作为范围的一部分。
  • access_type_valueaccess_type_key属性的值。 对于Google,您需要offline传递值,以便服务器在访问令牌之外还包括刷新令牌。

图2显示了示例客户端代码的index.html页面。 在Eclipse中成功配置项目并将其部署到Tomcat后,应该会看到此页面。

图2.测试客户端主页

客户端提供了您需要了解的有关OAuth 2.0的两个基本操作。 首先,客户端显示如何从服务器获取访问令牌。 其次,客户端展示了如何使用现有的访问令牌从服务器访问受保护的资源。

要运行客户端:

  • 首先,将所有必需的值放在Oauth2Client.config文件中。
  • 单击开始测试获取访问令牌。 HTTP GET请求发送到OAuth2Client Servlet,可通过以下URI http:// localhost:8080 / OAuth2.0_AuthCode / handler访问。
  • 用户界面代码将以下查询参数作为对OAuth2Client servlet的调用的一部分传递: caller=token (access token request), caller=resource (access protected resource request)

清单6中的客户端代码摘自OAuth2Client类的doGet方法。

清单6.示例客户端的doGet方法的节选
String caller = request.getParameter(OAuthConstants.CALLER);
String code = request.getParameter(OAuthConstants.CODE);//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
List<String> invalidProps = OAuthUtils.validateInput(oauthDetails);if(invalidProps!=null && invalidProps.size() == 0){//Validation successfulif(OAuthUtils.isValid(caller)){//Request was sent from web application.//Check type of requestif(caller.equalsIgnoreCase(OAuthConstants.TOKEN)){//Request for Access tokenoauthDetails.setAccessTokenRequest(true);String location =                    OAuthUtils.getAuthorizationCode(oauthDetails);//Send redirect to location returned by endpointresponse.sendRedirect(location);return;}else{//Request for accessing protected resourceif(!OAuthUtils.isValid(oauthDetails.getResourceServerUrl())){invalidProps.add(OAuthConstants.RESOURCE_SERVER_URL);}if(!OAuthUtils.isValid(oauthDetails.getAccessToken())){if(!OAuthUtils.isValid(oauthDetails.getRefreshToken())){invalidProps.add(OAuthConstants.REFRESH_TOKEN);}}if(invalidProps.size() > 0){sendError(response, invalidProps);return;}Map<String,String> map = OAuthUtils.getProtectedResource(oauthDetails);response.getWriter().println(new Gson().toJson(map));return;}}else if(OAuthUtils.isValid(code)){//Callback from endpoint with code.Map<String,String> map = OAuthUtils.getAccessToken(oauthDetails, code);response.getWriter().println(new Gson().toJson(map));return;}else{//Invalid request/error responseString queryString = request.getQueryString();String error = "Invalid request";if(OAuthUtils.isValid(queryString)){//Endpoint returned an errorerror = queryString;}response.getWriter().println(error);return;}}else{//Input is not valid. Send errorsendError(response, invalidProps);return;}

清单6的注释:

  • 客户端检索查询参数, callercode 。 如果请求是通过用户界面发送的(如前所示),则caller参数将具有有效值; 否则,该请求是作为重定向调用的一部分从授权服务器发送的,并且code将具有有效值。
  • 然后,客户端代码通过读取OAuth2Client.config文件中提供的属性来创建OAuthDetails bean。
  • 然后验证Bean的正确性和完整性。 如果找到任何无效或缺少的属性,则会将具有缺少/不正确的属性的适当错误响应发送到用户界面。
  • 然后,客户端代码继续验证请求的操作,并调用适当的操作。

访问令牌请求

清单7中的代码演示了如何发出授权代码请求。

清单7.授权代码请求代码
HttpPost post = new HttpPost(oauthDetails.getAuthenticationServerUrl());
String location = null;String state = oauthDetails.getState();List<BasicNameValuePair> parametersBody = new ArrayList<BasicNameValuePair>();parametersBody.add(new BasicNameValuePair(OAuthConstants.RESPONSE_TYPE,OAuthConstants.CODE));parametersBody.add(new BasicNameValuePair(OAuthConstants.CLIENT_ID,oauthDetails.getClientId()));parametersBody.add(new BasicNameValuePair(OAuthConstants.REDIRECT_URI,oauthDetails.getRedirectURI()));if (isValid(oauthDetails.getScope())) {parametersBody.add(new BasicNameValuePair(OAuthConstants.SCOPE,oauthDetails.getScope()));
}if (isValid(oauthDetails.getApprovalPromptValue())) {parametersBody.add(new BasicNameValuePair(oauthDetails.getApprovalPromptKey(), oauthDetails.getApprovalPromptValue()));
}if (isValid(oauthDetails.getAccessTypeValue())) {parametersBody.add(new BasicNameValuePair(oauthDetails.getAccessTypeKey(), oauthDetails.getAccessTypeValue()));
}if (isValid(state)) {parametersBody.add(new BasicNameValuePair(OAuthConstants.STATE,oauthDetails.getState()));
}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();System.out.println("Code " + code);Map<String, String> map = handleURLEncodedResponse(response);if (OAuthConstants.HTTP_SEND_REDIRECT == code) {location = getHeader(response.getAllHeaders(),OAuthConstants.LOCATION_HEADER);if (location == null) {System.out.println("The endpoint did not pass in valid location header for redirect");throw new RuntimeException("The endpoint did not pass in valid location header for redirect");}} else {System.out.println("Was expecting code 302 from endpoint to indicate redirect. Recieved httpCode "+ code);throw new RuntimeException("Was expecting code 302 from endpoint to indicate redirect. Recieved httpCode "+ code);}} catch (ClientProtocolException e) {// TODO Auto-generated catch blocke.printStackTrace();throw new RuntimeException(e.getMessage());
} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();throw new RuntimeException(e.getMessage());
}return location;

清单7中的代码说明:

  • 该代码从创建HttpPost方法开始,该方法用于发送URL编码的参数。
  • response_typeclient_idredirect_uri是必填参数,包含在请求中。
  • 其它任选的参数,诸如statescopeapproval_prompt_key/value ,和access_type_key/value如果为他们有效值已在配置文件中提供均包括在内。
  • DefaultHttpClient用于向授权服务器发出请求。
  • 授权服务器验证请求参数,并使用302 HTTP重定向代码以及Location标头进行回复。
  • 该代码识别从授权服务器接收到的302,并从响应头中检索Location头。
  • Location标头包含客户端将用户代理(Web浏览器)重定向到的URI。 URI通常是资源所有者登录并向客户端提供批准的登录提示。
  • 位置URI的值返回到调用方法( OAuth2Client.doGet() )。
  • Oauth2Client.doGet()方法将响应重定向到位置URI。
  • 资源所有者的用户代理(Web浏览器)现在被重定向到登录页面/批准页面,资源所有者需要在其中登录并向发出请求的客户端提供批准。
  • 在资源所有者向客户端授予批准后,授权服务器使用原始授权代码请求中传递的重定向URI发送code

清单8中的代码显示了如何使用上一步中收到的代码进行最终访问令牌请求。

清单8.示例代码访问令牌请求
HttpPost post = new HttpPost(oauthDetails.getTokenEndpointUrl());String clientId = oauthDetails.getClientId();String clientSecret = oauthDetails.getClientSecret();String scope = oauthDetails.getScope();Map<String, String> map = new HashMap<String, String>();List<BasicNameValuePair> parametersBody = new ArrayList<BasicNameValuePair>();parametersBody.add(new BasicNameValuePair(OAuthConstants.GRANT_TYPE,oauthDetails.getGrantType()));parametersBody.add(new BasicNameValuePair(OAuthConstants.CODE,authorizationCode));parametersBody.add(new BasicNameValuePair(OAuthConstants.CLIENT_ID,clientId));if (isValid(clientSecret)) {parametersBody.add(new BasicNameValuePair(OAuthConstants.CLIENT_SECRET, clientSecret));}parametersBody.add(new BasicNameValuePair(OAuthConstants.REDIRECT_URI,oauthDetails.getRedirectURI()));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();map = handleResponse(response);accessToken = map.get(OAuthConstants.ACCESS_TOKEN);} catch (ClientProtocolException e) {// TODO Auto-generated catch blocke.printStackTrace();throw new RuntimeException(e.getMessage());} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();throw new RuntimeException(e.getMessage());}return map;

清单8的注释:

  • 该代码使用HttpPost方法向令牌端点发出访问令牌请求。
  • grant_typecodeclient_idredirect_urigrant_type参数。
  • 如果client_secret有效,则它也包含在请求中。
  • code的值是授权服务器在上一个请求中返回的代码。
  • 如果请求有效,则令牌端点返回访问令牌,如果请求用于脱机访问,则返回刷新令牌。
  • 请注意,作为此请求的一部分发送的重定向URI必须与作为授权代码请求的一部分发送的重定向URI相同。 令牌端点验证重定向URI与客户端应用程序中指定的重定向URI匹配,该数据可与令牌端点一起使用。

刷新访问令牌

如前所述,访问令牌本质上通常是临时的,通常一小时的寿命。 拥有刷新令牌可以使客户端自动刷新过期的访问令牌,而无需资源所有者重新登录并验证客户端。 清单9中的代码说明了这一点。

清单9.刷新访问令牌的示例代码
String clientId = oauthDetails.getClientId();
String clientSecret = oauthDetails.getClientSecret();
String scope = oauthDetails.getScope();
String refreshToken = oauthDetails.getRefreshToken();
Map<String, String> map = new HashMap<String, String>();if (!isValid(refreshToken)) {throw new RuntimeException("Please provide valid refresh token in config file");}List<BasicNameValuePair> parametersBody = new ArrayList<BasicNameValuePair>();parametersBody.add(new BasicNameValuePair(OAuthConstants.GRANT_TYPE,OAuthConstants.REFRESH_TOKEN));parametersBody.add(new BasicNameValuePair(OAuthConstants.REFRESH_TOKEN,oauthDetails.getRefreshToken()));if (isValid(clientId)) {parametersBody.add(new BasicNameValuePair(OAuthConstants.CLIENT_ID,clientId));}if (isValid(clientSecret)) {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;try {post.setEntity(new UrlEncodedFormEntity(parametersBody, HTTP.UTF_8));response = client.execute(post);int code = response.getStatusLine().getStatusCode();map = handleResponse(response);} catch (ClientProtocolException e) {// TODO Auto-generated catch blocke.printStackTrace();throw new RuntimeException(e.getMessage());} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();throw new RuntimeException(e.getMessage());}return map;

关于清单9的注释:

  • 该代码使用HttpPost方法将请求发送到令牌端点。
  • grant_typerefresh_token参数是必需的。
  • 如果有效,则client_id包括client_idclient_secretscope
  • 如果请求有效,则令牌端点返回一个新的访问令牌。

访问受保护的资源

清单10中的代码演示了如何使用访问令牌访问受保护的资源。 如果访问令牌已过期,则代码将刷新访问令牌,然后重试访问受保护的资源。

清单10.访问受保护资源的示例代码
String resourceURL = oauthDetails.getResourceServerUrl();Map<String, String> map = new HashMap<String, String>();HttpGet get = new HttpGet(resourceURL);get.addHeader(OAuthConstants.AUTHORIZATION,getAuthorizationHeaderForAccessToken(oauthDetails.getAccessToken()));DefaultHttpClient client = new DefaultHttpClient();HttpResponse response = null;String accessToken = null;int code = -1;try {response = client.execute(get);code = response.getStatusLine().getStatusCode();if (code == OAuthConstants.HTTP_UNAUTHORIZED|| code == OAuthConstants.HTTP_FORBIDDEN) {// Access token is invalid or expired.Regenerate the access// tokenSystem.out.println("Access token is invalid or expired. Refreshing access token....");map = refreshAccessToken(oauthDetails);accessToken = map.get(OAuthConstants.ACCESS_TOKEN);if (isValid(accessToken)) {// update the access tokenSystem.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 >= 400) {throw new RuntimeException("Could not access protected resource. Server returned http code: "+ code);}} else {throw new RuntimeException("Could not refresh access token");}}map = handleResponse(response);} catch (ClientProtocolException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();} finally {get.releaseConnection();}return map;

关于清单10的注释:

  • 此方法接受OauthDetails bean以及从配置文件中检索到的值。
  • 顾名思义,此方法使用简单的HttpGet方法来尝试从资源服务器检索受保护的资源。
  • 要向资源服务器进行身份验证,需要将访问令牌作为授权标头的一部分发送。 例如, Authorization: Bearer accessTokenValue
  • 该代码创建一个DefaultHttpClient来向资源服务器发出获取请求。
  • 如果从资源服务器收到的响应代码是401或403,则用于身份验证的访问令牌可能已过期或无效。
  • 下一步是重新生成访问令牌(请参见清单9)。
  • 成功重新生成访问令牌之后,代码将更新OauthDetails bean中的访问令牌值。 该代码还将get方法中的现有授权标头替换为新的访问令牌值。
  • 该代码现在再次发出访问受保护资源的请求。
  • 如果访问令牌有效且资源服务器URL正确,则您应该能够在控制台中看到响应的内容。

使用Salesforce.com测试客户端

在Salesforce.com上注册

Salesforce.com是流行的软件即服务(SaaS)应用程序,支持OAuth 2.0的授权码授予类型。

要在Salseforce.com上注册:

  1. 单击Login ,然后单击免费注册
  2. 完成注册以获取您的凭据。
  3. 除了用户名和密码,您还会收到安全令牌。 您提供的用于发出访问令牌请求的密码必须是您的密码和安全令牌的串联(例如password12312123 )。
  4. 您在应用创建过程中指定的重定向URI被salesforce.com用于与您通信以获取授权码授予类型。

使用Salesforce.com运行示例客户端

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

您可以在Java resources / src文件夹下找到Oauth2Client_salesforce.config文件。 此配置文件是为salesforce.com定制的,可以用作提供配置值以针对Salesforce.com进行测试的模板。

如前所述,在Tomcat服务器上运行Oauth2Client Web应用程序,以进入Test client start页面,如图3所示。

图3. Salesforce测试客户端页面

图3显示了测试客户端页面。 单击开始测试获取访问令牌。 接下来,您将看到关于Salesforce访问令牌请求的登录提示,如图4所示。

图4. Salesforce访问令牌请求(登录提示)

图4显示了从Salesforce.com收到302和Location标头后,客户端将用户代理(Web浏览器)重定向到的Salesforce登录页面。

登录后,您将看到Salesforce访问令牌请求批准提示,如图5所示。

图5. Salesforce访问令牌请求(批准提示)

图5显示了资源所有者的批准提示(登录后),以授予对VarunOAuth2.0 App的访问权限,这是请求访问资源所有者的数据的示例代码。

Salesforce访问令牌输出

在Salesforce批准提示上授予对客户端的访问权限后,令牌端点将以访问令牌和刷新令牌以及其他特定于Salesforce的数据进行响应。 您应该在Eclipse控制台窗口中看到输出,如清单11所示。

清单11. Salesforce访问令牌输出
********** Response Received **********id = https://login.salesforce.com/id/00D90000000mQaYEAU/00590000001HCB7AAOissued_at = 1408356835704scope = full refresh_tokeninstance_url = https://ap1.salesforce.comtoken_type = Bearerrefresh_token = 5Aep8617VFpoP.M.4vPT_5eQXhIJTvFPNyK2GaBz7xFooRQE590MJSZNVqfTXKUqoiZH_yhm_ZpaVsmpid_token = eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjE5MCJ9.eyJleHAiOjE0MDgzNTY5NTUsInN1YiI6Imh0dHBzOi8vbG9naW4uc2FsZXNmb3JjZS5jb20vaWQvMDBEOTAwMDAwMDBtUWFZRUFVLzAwNTkwMDAwMDAxSENCN0FBTyIsImF0X2hhc2giOiJ3eWJpZ1NRTEtaNjdiYlRxWUJxNEVnIiwiYXVkIjoiM01WRzlZNmRfQnRwNHhwNXhLcHgxcFBtcFZidnlUV09Gd2FWbkxwOFpDYjRZVjBRX2FJcHI2WTZVazd1ZHcxcWtCTFZQcVVFNWY2blU1NW5xTWljMCIsImlzcyI6Imh0dHBzOi8vbG9naW4uc2FsZXNmb3JjZS5jb20iLCJpYXQiOjE0MDgzNTY4MzV9.W-r2-k-creIijmRmZ5qQff-bonjjtynNivJAv5XaSGedGhPavWlQpmn76B9k5vB7TWUDTX6y2NroTuIpBi-F2jrO0dunN1giPfv-YKyrCYrpy75J7NXmnSnDGrKhhYgkcR7x9s9MLMoMD-Vf1wsJr58XU2He-UwfrihfkdJzvLKiWRNQfz1gCUwlNSws70AQSqrBfB6MHpLqE7ogG1M3SOp6B4hbcA8NC_zwnvJwIDmF4t3_rf6VsgPuPjV_t4PphBhbrln7sm4b9OMcRRycc8WcCvgBvNPjI37uImciDYUGIP25NEy5sRM3mEU392YlmR5AoHUqOVOqdO9DS1ULWxBy3Q-Fp1wyKYyWiCrUMXe5QdtmeBmkpzptCKXwAhfxhLBdai4bBFfh8K3If4UP-WeNcpMwNkiRhVElwntlqtCPaSs4BLiZGonpLLgwET-f_Iyxs4BauCNvyWDbme_2it2V5AEHgJoKvuf2oU6hD8-Sit8MsdEdc2ugf-nk96QJt5px3QvChfDIE8B7W5trzXagkvzVcXXJV06zJbDUf-ioz7zDTI4Popkxlb31cQiaLAtz2IxIUtjZAfAcTXJaxi8txjV8glqS8Z61145bUaitXgGmZhZAqeefrqLneyCDD--EPNWDIdQYSPhRPbtFb5Aa89AMDNIePxTNnIWShNsaccess_token = 00D90000000mQaY!AQ8AQMgSI4eZOjvKJGVPuWISCkuS1WC0R6gOWpMg57bMwVWGkyS9_Wraa5ooMrjTfaqMmXmXlgParPk1rjn0vH5BxbNRq3W0signature = o1VBoC/PzvMw08hZGxYvXLiV/SXQirHBl8qOrk1Mu6Q=

从Salesforce服务器检索用户信息

有了访问令牌后,您就可以从Salesforce提出访问资源所有者的帐户信息的请求,这需要OAuth 2.0身份验证。

使用访问令牌更新Oauth2Client.confg文件并刷新令牌。 还使用您要测试的资源服务器URL设置资源服务器URL属性。 例如,您可以将其设置为Salesforce返回的id字段,作为访问令牌响应的一部分。 此id字段用于访问资源所有者的帐户信息(例如, https://login.salesforce.com/id/00D90000000mQaYEAU/00590000001HCB7AAO )。

刷新项目,然后在Tomcat服务器上再次运行该项目。 单击开始测试访问受保护的资源。

您的Eclipse控制台窗口应显示类似于清单12的输出。

清单12.受Salesforce保护的资源输出
********** Response Received **********addr_city = nullemail_verified = truelocale = en_USaddr_state = Unknownasserted_user = truenick_name = vern.ojha1********id = https://login.salesforce.com/id/00D9000000QaYEAU/005900001HCB7AAOfirst_name = varuntimezone = America/Los_Angelesusername = *******mobile_phone = nulluser_id = ************addr_street = nullstatus = {"created_date":null,"body":null}user_type = STANDARDurls = {"sobjects":"https:\/\/ap1.salesforce.com\/services\/data\/v{version}\/sobjects\/","feeds":"https:\/\/ap1.salesforce.com\/services\/data\/v{version}\/chatter\/feeds","users":"https:\/\/ap1.salesforce.com\/services\/data\/v{version}\/chatter\/users","query":"https:\/\/ap1.salesforce.com\/services\/data\/v{version}\/query\/","enterprise":"https:\/\/ap1.salesforce.com\/services\/Soap\/c\/{version}\/00D90000000mQaY","recent":"https:\/\/ap1.salesforce.com\/services\/data\/v{version}\/recent\/","feed_items":"https:\/\/ap1.salesforce.com\/services\/data\/v{version}\/chatter\/feed-items","search":"https:\/\/ap1.salesforce.com\/services\/data\/v{version}\/search\/","partner":"https:\/\/ap1.salesforce.com\/services\/Soap\/u\/{version}\/00D90000000mQaY","rest":"https:\/\/ap1.salesforce.com\/services\/data\/v{version}\/","groups":"https:\/\/ap1.salesforce.com\/services\/data\/v{version}\/chatter\/groups","metadata":"https:\/\/ap1.salesforce.com\/services\/Soap\/m\/{version}\/00D90000000mQaY","profile":"https:\/\/ap1.salesforce.com\/0000001CB7AAO"}mobile_phone_verified = falseis_app_installed = truephotos = {"picture":"https:\/\/c.ap1.content.force.com\/profilephoto\/005\/F","thumbnail":"https:\/\/c.ap1.content.force.com\/profilephoto\/005\/T"}display_name = varun ojhalast_modified_date = 2013-06-04T07:43:42.000+0000email = **************addr_country = INorganization_id = 00D90000000mQaYEAUlast_name = ojhautcOffset = -28800000active = truelanguage = en_USaddr_zip = 560071

如您所见,通过使用OAuth 2.0进行身份验证,您可以从Salesforce成功访问资源所有者的帐户信息。 配置文件中提供的访问令牌过期后,客户端将在下一个请求中自动重新生成访问令牌,并使用该令牌来获取资源服务器URL上可用的受保护资源。

向Google注册

Google使用OAuth 2.0对API进行身份验证,这些API可用于访问GoogleDrive,TaskQueue和CloudSQL等服务。 您可以按照https://developers.google.com/accounts/docs/OAuth2?hl=ES上的说明,设置一个应用程序来通过Google测试您的OAuth 2.0客户端。

使用Google运行客户端

既然您已经设置了符合OAuth 2.0的服务器,就可以测试客户端并从服务器中检索受保护的信息了。

您可以在Java resources / src文件夹下找到Oauth2Client_Google.config文件。 该配置文件是针对Google服务定制的,可以用作提供配置值的模板。

如前所述 ,在Tomcat服务器上运行Oauth2Client Web应用程序。 获取访问令牌和访问受保护的资源操作的流程和输出如图6所示。

图6.访问令牌请求(登录提示)

图6显示了从Google接收到302和Location标头后,客户端将用户代理(网络浏览器)重定向到的Google登录页面。

图7显示了资源所有者的批准提示(登录后),以授予对Cast Iron App的访问权限,该应用程序正在请求访问资源所有者的数据。

图7.访问令牌请求(批准提示)

资源所有者向客户端授予访问权限后,令牌端点将使用访问令牌和刷新令牌进行响应。 您应该在控制台窗口中看到类似于清单13所示的输出。

清单13。
********** Response Received **********expires_in = 3600token_type = Bearerrefresh_token = 1/TtCxaFlKMRsHeIlxrY-2ZJIO8DcRmQEiQ_2Wxw8access_token = ya29.ZQDpI-ahF6TMURwAAABqBu-2-U0_lUWfbwh053j3db3PzaNXV4k_k6fc_VT7uQ

从Google服务器检索用户信息

有了访问令牌后,您就可以请求访问资源所有者的GoogleDrive信息,这需要OAuth 2.0身份验证。

使用访问令牌和刷新令牌更新Oauth2Client.confg文件,并使用要测试的资源服务器URL填充资源服务器url属性。 我将用https://www.googleapis.com/drive/v2/about替换它,这是GoogleDrive帐户信息URL。

现在,刷新项目,然后再次在Tomcat服务器上运行它。 单击开始测试访问受保护的资源。

您应该在控制台窗口中看到类似于清单14所示的代码片段的输出。

清单14。
********** Response Received **********name = Varun Ojhafeatures = [{"featureName":"ocr"},{"featureName":"translation","featureRate":0.5}]quotaBytesTotal = 16106127360largestChangeId = 1911rootFolderId = 0ALupA2Opqyp1Uk9PVAquotaType = LIMITEDquotaBytesByService = [{"bytesUsed":"229","serviceName":"DRIVE"},{"bytesUsed":"1154860956","serviceName":"GMAIL"},{"bytesUsed":"568174452","serviceName":"PHOTOS"}]permissionId = 01822620516456565194quotaBytesUsedInTrash = 119332

如您所见,通过使用OAuth 2.0进行身份验证,您可以从GoogleDrive成功访问资源所有者的帐户信息。

在配置文件中提供的访问令牌到期后,客户端会在下一个请求中自动重新生成访问令牌,并使用重新生成的令牌来检索资源服务器URL上可用的受保护资源。

使用IBM端点测试客户端

此客户端示例代码已通过与OAuth 2.0兼容的IBM端点(例如IBMWebsphere®Application Server和IBMDatapower.®)成功测试。

在“ 使用OAuth:在WebSphere Application Server中启用OAuth服务提供程序 ”中可以找到在Websphere Application Server上设置OAuth 2.0服务器的说明。

可以像测试Salesforce和Google一样测试IBM端点。

结论

本教程系列的第3部分介绍了授权码授予类型的基础。 它演示了如何编写Java代码中的通用OAuth 2.0客户端以连接到多个OAuth 2.0兼容的端点并从中检索受保护的资源。 可以将“ 下载 ”中的样本客户机Web项目导入到Eclipse环境中,并将其用作创建自定义Oauth 2.0客户机的起点。


翻译自: https://www.ibm.com/developerworks/java/library/se-oauthjavapt3/index.html

软件授权注册码_授权码授予相关推荐

  1. r统计建模与r软件期末考试题_“统计学诺贝尔奖”授予 R 语言软件工程师 Hadley Wickham | 科研圈日报...

    "科研圈日报"主要关注科研圈与研究者个体.科研圈与更广阔的社会环境之间的重要互动.点击 这里 可以查看往期内容. · 学术荣誉 "统计学诺贝尔奖"授予 R 语言 ...

  2. oauth2.0授权码_OAUTH 2.0授权码授予

    oauth2.0授权码 OAuth 2.0提供了许多安全流程(或授权类型),以允许一个应用程序访问另一个应用程序中的用户数据. 在此博客中,我们将介绍OAuth 2.0授权:授权代码授权. 首先,有许 ...

  3. OAUTH 2.0授权码授予

    OAuth 2.0提供了许多安全性流程(或授权类型),以允许一个应用程序访问另一个应用程序中的用户数据. 在此博客中,我们将介绍OAuth 2.0授权:授权代码授权. 首先,有许多定义: 客户端 :用 ...

  4. DCC尺寸链计算与公差仿真分析软件 软件应用案例以及授权文件

    DCC尺寸链计算与公差仿真分析软件,是解决产品性能.质量问题,降低企业生产成本的有力工具.广泛应用于:核工业.航空航天航海.医疗设备.军工装备.电子电气.轨道交通.发动机.船舶装备.汽车.发动机等领域 ...

  5. wincc怎样创建计算机用户,wincc73授权教程_计算机软件及应用_IT计算机_专业资料...

    wincc73授权教程_计算机软件及应用_IT计算机_专业资料 (5页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦! 9.9 积分 安装完wince 7.3 ...

  6. 微信授权2.0php源码,微信网页授权(OAuth2.0) PHP 源码简单实现

    微信网页授权(OAuth2.0) PHP 源码简单实现 来源:中文源码网    浏览: 次    日期:2018年9月2日 [下载文档:  微信网页授权(OAuth2.0) PHP 源码简单实现.tx ...

  7. 在线电脑配置PHP源码,域名授权系统PHP源码 V2.7.0 支持盗版追踪

    最新漂亮简洁大气的域名授权系统PHP源码,域名授权系统PHP版,功能强大带有后台,经过版本升级,全新美观大气的UI洁面! 支持盗版追踪,与卡密系统对接购买卡密对域名进行授权,支持授权代码.到期时间代码 ...

  8. php授权验证系统源码-全解开源版

    简介: php授权验证系统源码全解开源版,正版授权查询管理. 安装方法:上传PHP环境,访问域名instll,根据提示自动安装! 网盘下载地址: http://kekewl.org/MBJa7XXNk ...

  9. mysql授权许可_分析MySQL的授权许可

    MySQL是开源软件,但开源不意味着免费,开源软件的使用应遵循该软件提供的使用授权许可.MySQL的授权许可是英文的,而且一直以来没有权威的中文译本,所以很多人都不清楚其中的细节. 最近我在做一些AS ...

  10. 微商助理 防伪防窜货溯源代理授权查询系统源码

    源码介绍 微商助理防伪防窜货溯源代理授权查询系统源码支持二维码扫码查询 程序架构:PHP+Mysql PHP版本要求PHP5.4以上(推荐PHP5.4) 把源码文件上传到网站根目录,此套系统功能较多, ...

最新文章

  1. 天地伟业tiandy如何连手机_关注 | 天地盖手工盒裱纸选铜版纸还是白牛皮纸?
  2. c#web页面显示弹窗_C#中三种弹出信息窗口的方式
  3. Android.对话框(AlertDialog/Toast/Snackbar)
  4. 在linux下添加路由
  5. 怎么将一个数字高低位互换_多彩数字 多彩童年——东城幼儿园玩具研究教学案例...
  6. css如何重置触发动画,如何通过JavaScript重新触发WebKit CSS动画?
  7. Python中 模块、包、库
  8. JZOJ5775 农夫约的假期
  9. Ryu控制器正则表达式字符串 r'[0-9]{1,4}|all' 分析
  10. 盛大剥离新业务:陈大年控股
  11. 华三路由器RIP协议详细配置
  12. Openwrt开发笔记(3)—— 修改路由的网关地址和无线SSID 密码
  13. Vue上传图片裁剪预览插件vue-img-cutter的使用
  14. oracle tns 启动失败,Oracle 监听启动失败 TNS-12555: TNS:permission denied 解决方案
  15. 又一暴强的截图工具 ShareX
  16. Win32 IME 编程心得【转】
  17. OSPF —— 多区域部署 + ABR + ASBR + 路由重分发
  18. 清华大学操作系统课程实验
  19. stm32使用AD转换读取光敏电阻的值(光敏电阻5516)
  20. 《硬件接入》3288板刷机及屏幕参数配置探索

热门文章

  1. 【浏览器硬件交互篇】浏览器js调用摄像头拍照
  2. [论文写作笔记] C11论文查重原理及降重
  3. Python 机器学习经典实例
  4. PLSQL导入SQL文件
  5. can通道采样频率_CAN波特率计算
  6. centos Linux 上 怎么命令行安装和卸载QQ
  7. delphi7IDE技巧
  8. extjs4.0视频教程
  9. java excel 2007兼容包_Microsoft Office 2007兼容包
  10. 模糊数学 计算机智能,模糊数学与人智能技术.pdf