OAuth 2.0

Posted youzhongmin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OAuth 2.0相关的知识,希望对你有一定的参考价值。

什么是 OAuth 2.0

  OAuth 是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用。目前,OAuth 的最新版本为 2.0。OAuth 允许用户提供一个令牌,而不是用户名和密码来访问他们存放在特定服务提供者的数据。每一个令牌授权一个特定的网站(例如,视频编辑网站)在特定的时段(例如,接下来的2小时内)内访问特定的资源(例如仅仅是某一相册中的视频)。这样,OAuth 允许用户授权第三方网站访问他们存储在另外的服务提供者上的信息,而不需要分享他们的访问许可或他们数据的所有内容。

OAuth 2.0 的核心概念

  • resource owner:资源所有者,指终端的“用户”(user)
  • resource server:资源服务器,即服务提供商存放受保护资源。访问这些资源,需要获得访问令牌(access token)。它与认证服务器,可以是同一台服务器,也可以是不同的服务器。如果,我们访问新浪博客网站,那么如果使用新浪博客的账号来登录新浪博客网站,那么新浪博客的资源和新浪博客的认证都是同一家,可以认为是同一个服务器。如果,我们是新浪博客账号去登录了知乎,那么显然知乎的资源和新浪的认证不是一个服务器。
  • client:客户端,代表向受保护资源进行资源请求的第三方应用程序。
  • authorization server: 授权服务器, 在验证资源所有者并获得授权成功后,将发放访问令牌给客户端。        ## OAuth 2.0 的认证流程

OAuth 2.0 的认证流程

  • (A)用户打开客户端以后,客户端请求资源所有者(用户)的授权。
  • (B)用户同意给予客户端授权。
  • (C)客户端使用上一步获得的授权,向认证服务器申请访问令牌。
  • (D)认证服务器对客户端进行认证以后,确认无误,同意发放访问令牌。
  • (E)客户端使用访问令牌,向资源服务器申请获取资源。
  • (F)资源服务器确认令牌无误,同意向客户端开放资源。

其中,用户授权有四种模式:

  • 授权码模式(authorization code)
  • 简化模式(implicit)
  • 密码模式(resource owner password credentials)
  • 客户端模式(client credentials)

授权码模式(authorization code)

技术分享图片

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

授权码请求

对应于步骤 (A) 和 (B) 的授权码请求如 图 1 所示。在步骤 (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,并将授权码包含为重定向 URI 的查询组件的一部分,这里采用的是 application/x-www-form-urlencoded 格式。

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-urlencoded
             grant_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 是有效的。在存在机密性客户端的情况下,授权服务器也使用在其请求的主体或 Authorization 标头中传递的客户端凭据来对客户端进行身份验证。

访问令牌响应

这对应于 图 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-urlencoded
grant_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"
}

简化模式(implicit)

  在简化模式中,Authorization Code和Access Token都由授权服务器生成和验证,而最终只用到Access Token,这让Authorization Code显得无足轻重。因此,授权码简化模式,去掉了Authorization Code的申请流程,从而通过User-Agent(Browser)直接申请Access Token。

密码模式(resource owner password credentials)

技术分享图片

  该模式下,需要用户将自身的account ID和password交由client,client将使用它们来申请access token,整个过程会将用户信息暴露。因此,除非client十分可靠(例如硬件设备,系统APP),否则,不建议使用该模式。

(A)用户向客户端提供用户名和密码。

(B)客户端将用户名和密码发给认证服务器,向后者请求令牌。

(C)认证服务器确认无误后,向客户端提供访问令牌。

Request:

POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=password&username=johndoe&password=A3ddj3w

Response:

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,
       "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
       "example_parameter":"example_value"
}

客户端模式(client credentials)

技术分享图片

该模式下,并不存在对个体用户授权的行为,被授权的主体为client。因此,该模式可用于对某类用户进行集体授权。

(A)客户端向认证服务器进行身份认证,并要求一个访问令牌。

(B)认证服务器确认无误后,向客户端提供访问令牌。

Request:

POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials

Response:

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"
}

实践

客户端

需要加入的jar包:org.apache.oltu.oauth2.client-1.0.1.jar

package authclient;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.oltu.oauth2.client.OAuthClient;
import org.apache.oltu.oauth2.client.URLConnectionClient;
import org.apache.oltu.oauth2.client.request.OAuthBearerClientRequest;
import org.apache.oltu.oauth2.client.request.OAuthClientRequest;
import org.apache.oltu.oauth2.client.response.OAuthAccessTokenResponse;
import org.apache.oltu.oauth2.client.response.OAuthResourceResponse;
import org.apache.oltu.oauth2.common.OAuth;
import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
import org.apache.oltu.oauth2.common.message.types.GrantType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

@RequestMapping("/server")
@Controller
public class ClientController {
	 String clientId = null;
	 String clientSecret = null;
	 String accessTokenUrl = null;
	 String userInfoUrl = null;
	 String redirectUrl = null;
	 String response_type = null;
	 String code= null;
	 //提交申请code的请求
	 @RequestMapping(value="/requestServerCode",produces="application/json;charset=UTF-8")
	 public String requestServerFirst(HttpServletRequest request, 
			 HttpServletResponse response, RedirectAttributes attr)
					 throws OAuthProblemException{
	      clientId = "clientId";
	      clientSecret = "clientSecret";
	      accessTokenUrl = "responseCode";
	      redirectUrl = "http://localhost:8080/OAuthClientTest/server/callbackCode";
	      response_type = "code";
	      System.out.println("================");
	      OAuthClient oAuthClient =new OAuthClient(new URLConnectionClient());
	      String requestUrl = null;
	      try {
	        //构建oauth的请求。设置请求服务地址(accessTokenUrl)、clientId、response_type、redirectUrl
	        OAuthClientRequest accessTokenRequest = OAuthClientRequest
	        		.authorizationLocation(accessTokenUrl)
	                .setResponseType(response_type)
	                .setClientId(clientId)
	                .setRedirectURI(redirectUrl)
	                .buildQueryMessage();
	        requestUrl = accessTokenRequest.getLocationUri();
	        System.out.println(requestUrl);
	      } catch (OAuthSystemException e) {
	        e.printStackTrace();
	      }
	      return "redirect:http://localhost:8080/OAuthServerTest/"+requestUrl ;
	   }
	 //接受客户端返回的code,提交申请access token的请求,对应上图中的步骤三
	 @RequestMapping(value="/callbackCode",produces="application/json;charset=UTF-8")
	 public Object toLogin(HttpServletRequest request) throws OAuthProblemException{
		 clientId = "clientId";
		 clientSecret = "clientSecret";
		 accessTokenUrl="http://localhost:8080/OAuthServerTest/responseAccessToken";
		 userInfoUrl = "userInfoUrl";
	     redirectUrl = "http://localhost:8080/OAuthClientTest/server/accessToken";
	     HttpServletRequest httpRequest = (HttpServletRequest) request;
	     OAuthClient oAuthClient = new OAuthClient(new URLConnectionClient());
	     System.out.println("--------客户端端/callbackCode-----------------");
	     try {
	    	 OAuthClientRequest accessTokenRequest = OAuthClientRequest
	    			 .tokenLocation(accessTokenUrl)
	                 .setGrantType(GrantType.AUTHORIZATION_CODE)
	                 .setClientId(clientId)
	                 .setClientSecret(clientSecret)
	                 .setCode(httpRequest.getParameter("code"))
	                 .setRedirectURI(redirectUrl)
	                 .buildQueryMessage();
	    	 //去服务端请求access token,并返回响应
	    	 OAuthAccessTokenResponse oAuthResponse = oAuthClient.accessToken(accessTokenRequest, OAuth.HttpMethod.POST);
	         //获取服务端返回过来的access token 
	         String accessToken = oAuthResponse.getAccessToken();
	         //查看access token是否过期
	         Long expiresIn = oAuthResponse.getExpiresIn();
	         return "redirect:http://localhost:8080/OAuthClientTest/server/accessToken?accessToken="+accessToken;
	        } catch (OAuthSystemException e) {
	            e.printStackTrace();
	        }
	        return null;
	    }
	 //接受服务端传回来的access token,由此token去请求服务端的资源(用户信息等),对应上图中的步骤五
	 @RequestMapping(value="/accessToken",produces="application/json;charset=UTF-8")
	 public ModelAndView accessToken(String accessToken) {
		 userInfoUrl = "http://localhost:8080/OAuthServerTest/userInfo";
	     OAuthClient oAuthClient = new OAuthClient(new URLConnectionClient());
	     System.out.println("--------客户端端/accessToken-----------------");
	     try {
	    	 OAuthClientRequest userInfoRequest = new OAuthBearerClientRequest(userInfoUrl)
	    			 .setAccessToken(accessToken).buildQueryMessage();
	         OAuthResourceResponse resourceResponse = oAuthClient.resource(userInfoRequest,
	        		 OAuth.HttpMethod.GET, OAuthResourceResponse.class);
	         String username = resourceResponse.getBody();
	         System.out.println("--------客户端端/accessToken-----------------"+username);
	         ModelAndView modelAndView = new ModelAndView("usernamePage");
	         modelAndView.addObject("username", username);
	         return modelAndView;
	         } catch (OAuthSystemException e) {
	            e.printStackTrace();
	        } catch (OAuthProblemException e) {
	            e.printStackTrace();
	        }
	        return null;
	    }
}

服务端

需要加入的jar包:org.apache.oltu.oauth2.authzserver-1.0.1.jar和org.apache.oltu.oauth2.resourceserver-1.0.1.jar

向客户端返回授权码code的controller方法

package authserver;

import java.net.URI;
import java.net.URISyntaxException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.oltu.oauth2.as.request.OAuthAuthzRequest;
import org.apache.oltu.oauth2.as.response.OAuthASResponse;
import org.apache.oltu.oauth2.common.OAuth;
import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
import org.apache.oltu.oauth2.common.message.OAuthResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import service.UserService;

@Controller
public class ServerController{
	@Autowired
	private UserService userService;
	//向客户端返回授权许可码 code
	@RequestMapping(value="/responseCode",produces="application/json;charset=UTF-8")
	public Object toShowUser(Model model,  HttpServletRequest request){
		System.out.println("----------服务端/responseCode------------");
		try {
			//构建OAuth授权请求 
			OAuthAuthzRequest oauthRequest =new OAuthAuthzRequest(request);
			/*oauthRequest.getClientId();
			oauthRequest.getResponseType();
	        oauthRequest.getRedirectURI();
	        System.out.println(oauthRequest.getClientId());
	        System.out.println(oauthRequest.getResponseType());
	        System.out.println(oauthRequest.getRedirectURI());*/
			if(oauthRequest.getClientId()!=null&&oauthRequest.getClientId()!="")
	           {
	           //设置授权码 
	                String authorizationCode ="authorizationCode";
	              //利用oauth授权请求设置responseType,目前仅支持CODE,另外还有TOKEN 
	                String responseType =oauthRequest.getParam(OAuth.OAUTH_RESPONSE_TYPE);
	              //进行OAuth响应构建
	                OAuthASResponse.OAuthAuthorizationResponseBuilder builder =
	                          OAuthASResponse.authorizationResponse(request, HttpServletResponse.SC_FOUND);
	              //设置授权码
	                builder.setCode(authorizationCode);
	              //得到到客户端重定向地址
	                String redirectURI =oauthRequest.getParam(OAuth.OAUTH_REDIRECT_URI);
	              //构建响应
	                final OAuthResponse response =builder.location(redirectURI).buildQueryMessage();
	                System.out.println("服务端/responseCode内,返回的回调路径:"+response.getLocationUri());
	                System.out.println("----------服务端/responseCode--------------------");
	               String responceUri =response.getLocationUri();
	              //根据OAuthResponse返回ResponseEntity响应
	                  HttpHeaders headers =new HttpHeaders();
	                  try {
	                 headers.setLocation(new URI(response.getLocationUri()));
	              } catch (URISyntaxException e) {
	                 // TODO Auto-generated catch block
	                 e.printStackTrace();
	              }
	                  return"redirect:"+responceUri;
	           }
	      } catch (OAuthSystemException e) {
	        e.printStackTrace();
	      } catch (OAuthProblemException e) {
	        e.printStackTrace();
	      }
	         System.out.println("----------服务端/responseCode------------------");
	      return null;
	   }
}

向客户端返回资源访问令牌accesstoken的controller方法

package authserver;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.oltu.oauth2.as.issuer.MD5Generator;
import org.apache.oltu.oauth2.as.issuer.OAuthIssuer;
import org.apache.oltu.oauth2.as.issuer.OAuthIssuerImpl;
import org.apache.oltu.oauth2.as.request.OAuthTokenRequest;
import org.apache.oltu.oauth2.as.response.OAuthASResponse;
import org.apache.oltu.oauth2.common.OAuth;
import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
import org.apache.oltu.oauth2.common.message.OAuthResponse;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import net.sf.json.JSONObject;

@Controller
public class AccessTokenController {
	//获取客户端的code码,向客户端返回access token
	   @RequestMapping(value="/responseAccessToken",method = RequestMethod.POST,produces="application/json;charset=UTF-8") 
	   public HttpEntity token(HttpServletRequest request){
		System.out.println("--------服务端/responseAccessToken----------开始-----------");
		OAuthIssuer oauthIssuerImpl=null;
	    OAuthResponse response=null;
	    //构建OAuth请求 
	    try {
	        OAuthTokenRequest oauthRequest =new OAuthTokenRequest(request);
	        String authCode =oauthRequest.getParam(OAuth.OAUTH_CODE);
	        String clientSecret = oauthRequest.getClientSecret();
	        if(clientSecret!=null||clientSecret!=""){
	           //生成Access Token
	               oauthIssuerImpl =new OAuthIssuerImpl(new MD5Generator());
	               final String accessToken =oauthIssuerImpl.accessToken();
	               System.out.println(accessToken);
	               System.out.println("--oooo---"+authCode+"======"+clientSecret);
	             //生成OAuth响应
	               response = OAuthASResponse
	                       .tokenResponse(HttpServletResponse.SC_OK)
	                       .setAccessToken(accessToken)
	                       .buildJSONMessage();
	        }
//	        String access_token = response.getBody().toString();
//	        String value = access_token.replace("access_token=", "");
//	        JSONObject jsonObject =  new JSONObject();
//	        jsonObject.put("access_token", value);
	        System.out.println("--------服务端/responseAccessToken-----");
	          //根据OAuthResponse生成ResponseEntity
	        return new ResponseEntity(response.getBody(), HttpStatus.valueOf(response.getResponseStatus()));
	      } catch (OAuthSystemException e) {
	        // TODO Auto-generated catch block
	        e.printStackTrace();
	      } catch (OAuthProblemException e) {
	        // TODO Auto-generated catch block
	        e.printStackTrace();
	      }
	        System.out.println("--------服务端/responseAccessToken---------------------");
	      return null;
	   }
	}

向客户端返回请求资源(username)的controller方法

package authserver;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.oltu.oauth2.common.OAuth;
import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
import org.apache.oltu.oauth2.common.message.OAuthResponse;
import org.apache.oltu.oauth2.common.message.types.ParameterStyle;
import org.apache.oltu.oauth2.common.utils.OAuthUtils;
import org.apache.oltu.oauth2.rs.request.OAuthAccessResourceRequest;
import org.apache.oltu.oauth2.rs.response.OAuthRSResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import domain.User;
import service.UserService;

@Controller
public class UserInfoController {
	@Autowired
	private UserService userService;
	@RequestMapping(value="/userInfo",produces="application/json;charset=UTF-8")
	public HttpEntity userInfo(HttpServletRequest request)throws OAuthSystemException{
		System.out.println("-----------服务端/userInfo---------");
		try {
			//获取客户端传来的OAuth资源请求
	        OAuthAccessResourceRequest oauthRequest = 
	        		new OAuthAccessResourceRequest(request, ParameterStyle.QUERY);
	        //获取Access Token
	        String accessToken =oauthRequest.getAccessToken(); 
	        System.out.println("accessToken");
	            //验证Access Token 
	            /*if (accessToken==null||accessToken=="") { 
	              // 如果不存在/过期了,返回未验证错误,需重新验证 
	            OAuthResponse oauthResponse = OAuthRSResponse 
	                    .errorResponse(HttpServletResponse.SC_UNAUTHORIZED) 
	                    .setError(OAuthError.ResourceResponse.INVALID_TOKEN) 
	                    .buildHeaderMessage(); 
	              HttpHeaders headers = new HttpHeaders(); 
	              headers.add(OAuth.HeaderType.WWW_AUTHENTICATE,  
	                oauthResponse.getHeader(OAuth.HeaderType.WWW_AUTHENTICATE)); 
	            return new ResponseEntity(headers, HttpStatus.UNAUTHORIZED); 
	            }  */
	            //返回用户名 
	            User user=userService.selectByPrimaryKey(1);
	            String username = accessToken+"---"+Math.random()+"----"+"youzhongmin";
	            System.out.println(username);
	            System.out.println("服务端/userInfo::::::ppp");
	            System.out.println("-----------服务端/userInfo----------------------------------------------------------");
	            return new ResponseEntity(username, HttpStatus.OK); 
	      } catch (OAuthProblemException e) {
	        // TODO Auto-generated catch block
	        e.printStackTrace();
	        //检查是否设置了错误码 
	        String errorCode =e.getError();
	        if (OAuthUtils.isEmpty(errorCode)) {
	              OAuthResponse oauthResponse = OAuthRSResponse 
	                     .errorResponse(HttpServletResponse.SC_UNAUTHORIZED) 
	                     .buildHeaderMessage(); 
	              HttpHeaders headers =new HttpHeaders(); 
	              headers.add(OAuth.HeaderType.WWW_AUTHENTICATE,  
	                oauthResponse.getHeader(OAuth.HeaderType.WWW_AUTHENTICATE)); 
	              return new ResponseEntity(headers, HttpStatus.UNAUTHORIZED); 
	            }
	            OAuthResponse oauthResponse = OAuthRSResponse 
	                     .errorResponse(HttpServletResponse.SC_UNAUTHORIZED) 
	                     .setError(e.getError()) 
	                     .setErrorDescription(e.getDescription()) 
	                     .setErrorUri(e.getUri()) 
	                     .buildHeaderMessage(); 
	            HttpHeaders headers =new HttpHeaders(); 
	            headers.add(OAuth.HeaderType.WWW_AUTHENTICATE,  
	            oauthResponse.getHeader(OAuth.HeaderType.WWW_AUTHENTICATE)); 
	            System.out.println("-----------服务端/userInfo------------------------------------");
	            return new ResponseEntity(HttpStatus.BAD_REQUEST); 
	      } 
	   }
}

  

以上是关于OAuth 2.0的主要内容,如果未能解决你的问题,请参考以下文章

Oauth 2.0 隐式授权有多安全?

OAuth 2.0 代码授权流程

Facebook OAuth 2.0“代码”和“令牌”

在 Angular 中实现 OAuth 2.0 授权代码授予

OpenId Connect 问题 - 授权代码流 (OAuth 2.0)

理解OAuth 2.0