1. 程式人生 > >Oauth2.0客戶端服務端示例

Oauth2.0客戶端服務端示例

https://blog.csdn.net/qq_28165595/article/details/80459185

 

前言
前面的理解OAuth2.0認證與客戶端授權碼模式詳解,我們大致瞭解了Oauth2.0授權模式四種的授權碼模式,清楚了授權碼模式的大致流程。這裡簡單的模擬一下基於授權碼模式的客戶端和服務端程式碼實現(這裡服務端包含的驗證服務端和資源服務端,都是在同一個應用中)。

回顧大致授權流程


圖中步驟1,請求授權,例如我們要登入csdn,這裡我們想用qq賬號登入,這時候就需要騰訊開放平臺進行授權,具體操作如下圖

這裡簡單模擬,在客戶端web專案中構造一個oauth的客戶端請求物件(OAuthClientRequest),在此物件中攜帶客戶端資訊(clientId、accessTokenUrl、response_type、redirectUrl),將此資訊放入http請求中,重定向到服務端。
上圖步驟2,在服務端web專案中接受第一步傳過來的request,從中獲取客戶端資訊,可以自行驗證資訊的可靠性。同時構造一個oauth的code授權許可物件(OAuthAuthorizationResponseBuilder),並在其中設定授權碼code,將此物件傳回客戶端。
上圖步驟3,在在客戶端web專案中接受第二步的請求request,從中獲得code。同時構造一個oauth的客戶端請求物件(OAuthClientRequest),此次在此物件中不僅要攜帶客戶端資訊(clientId、accessTokenUrl、clientSecret、GrantType、redirectUrl),還要攜帶接受到的code。再構造一個客戶端請求工具物件(oAuthClient),這個工具封裝了httpclient,用此物件將這些資訊以post的方式請求到服務端,目的是為了讓服務端返回資源訪問令牌。
上圖步驟4,在服務端web專案中接受第三步傳過來的request,從中獲取客戶端資訊和code,並自行驗證。再按照自己專案的要求生成訪問令牌(accesstoken),同時構造一個oauth響應物件(OAuthASResponse),攜帶生成的訪問指令(accesstoken),返回給第三步中客戶端的oAuthClient。oAuthClient接受響應之後獲取accesstoken。
上圖步驟5,此時客戶端web專案中已經有了從服務端返回過來的accesstoken,那麼在客戶端構造一個服務端資源請求物件(OAuthBearerClientRequest),在此物件中設定服務端資源請求URI,並攜帶上accesstoken。再構造一個客戶端請求工具物件(oAuthClient),用此物件去服務端靠accesstoken換取資源。
上圖步驟6,在服務端web專案中接受第五步傳過來的request,從中獲取accesstoken並自行驗證。之後就可以將客戶端請求的資源返回給客戶端了。
客戶端程式碼
/**
* @ClassName: ClientController
* @Description: Oauth客戶端
* @author qinhaihai
* @date 2018年5月24日
*
*/
@Controller
@RequestMapping("/clientController")
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("/requestServerCode")
public String requestServerCode(HttpServletRequest request, HttpServletResponse response)
throws OAuthProblemException{
clientId = "clientId";
accessTokenUrl = "responseCode";
redirectUrl = "http://localhost:8081/oauthclient01/clientController/callbackCode";
response_type = "code";
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的值----"+requestUrl);
} catch (OAuthSystemException e) {
e.printStackTrace();
}
return "redirect:http://localhost:8082/oauthserver/"+requestUrl ;
}

//接受客戶端返回的code,提交申請access token的請求,對應上圖中的步驟三
@RequestMapping("/callbackCode")
public Object toLogin(HttpServletRequest request) throws OAuthProblemException{
clientId = "clientId";
clientSecret = "clientSecret";
accessTokenUrl="http://localhost:8082/oauthserver/responseAccessToken";
userInfoUrl = "userInfoUrl";
redirectUrl = "http://localhost:8081/oauthclient01/clientController/accessToken";
HttpServletRequest httpRequest = (HttpServletRequest) request;
OAuthClient oAuthClient = new OAuthClient(new URLConnectionClient());
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:8081/oauthclient01/clientController/accessToken?accessToken="+accessToken;
} catch (OAuthSystemException e) {
e.printStackTrace();
}
return null;
}

//接受服務端傳回來的access token,由此token去請求服務端的資源(使用者資訊等),對應上圖中的步驟五
@RequestMapping("/accessToken")
public ModelAndView accessToken(String accessToken) {
userInfoUrl = "http://localhost:8082/oauthserver/userInfo";
OAuthClient oAuthClient = new OAuthClient(new URLConnectionClient());
try {
OAuthClientRequest userInfoRequest = new OAuthBearerClientRequest(userInfoUrl)
.setAccessToken(accessToken).buildQueryMessage();
OAuthResourceResponse resourceResponse = oAuthClient.resource(userInfoRequest, OAuth.HttpMethod.GET, OAuthResourceResponse.class);
String username = resourceResponse.getBody();
ModelAndView modelAndView = new ModelAndView("usernamePage");
modelAndView.addObject("username", username);
return modelAndView;
} catch (OAuthSystemException e) {
e.printStackTrace();
} catch (OAuthProblemException e) {
e.printStackTrace();
}
return null;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
服務端程式碼
/**
* @ClassName: AuthorizeController
* @Description: 服務端授權Controller
* @author aiqinhai
* @date 2018年5月24日 下午10:00:01
*/
@Controller
public class AuthorizeController{
//向客戶端返回授權許可碼 code,對應上圖中的步驟二
@RequestMapping("/responseCode")
public Object responseCode(Model model,HttpServletRequest request){
try {
//構建OAuth 授權請求
OAuthAuthzRequest oauthRequest = new OAuthAuthzRequest(request);
System.out.println("授權伺服器獲取的clientID----"+oauthRequest.getClientId());
System.out.println("返回型別----"+oauthRequest.getResponseType());
System.out.println("重定向地址---"+oauthRequest.getRedirectURI());
if(oauthRequest.getClientId()!=null&&oauthRequest.getClientId()!=""){
//設定授權碼
String authorizationCode = "authorizationCode";
//進行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();
String responceUri =response.getLocationUri();
System.out.println("redirectURI是----"+redirectURI);
System.out.println("responceUri是----"+responceUri);
//根據OAuthResponse返回ResponseEntity響應
HttpHeaders headers = new HttpHeaders();
try {
headers.setLocation(new URI(responceUri));
} catch (URISyntaxException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return "redirect:"+responceUri;
}
} catch (OAuthSystemException e) {
e.printStackTrace();
} catch (OAuthProblemException e) {
e.printStackTrace();
}
return null;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
上面的responseCode,對應了上圖的步驟二,返回authorizationCode授權碼到客戶端。

/**
*
* @ClassName: AccessTokenController
* @Description: 根據授權碼生成accessToken
* @author aiqinlhai
* @date 2018年5月24日
*/
@Controller
public class AccessTokenController {

//獲取客戶端的code碼,向客戶端返回access token
@RequestMapping(value="/responseAccessToken",method = RequestMethod.POST)
public HttpEntity token(HttpServletRequest request){
OAuthIssuer oauthIssuerImpl=null;
OAuthResponse response=null;
//構建OAuth請求
try {
OAuthTokenRequest oauthRequest = new OAuthTokenRequest(request);
String authCode = oauthRequest.getParam(OAuth.OAUTH_CODE);
System.out.println("客戶端傳過來的授權碼是----"+authCode);
String clientSecret = oauthRequest.getClientSecret();
if(clientSecret!=null||clientSecret!=""){
//生成Access Token
oauthIssuerImpl = new OAuthIssuerImpl(new MD5Generator());
final String accessToken = oauthIssuerImpl.accessToken();
System.out.println(accessToken);
//生成OAuth響應
response = OAuthASResponse
.tokenResponse(HttpServletResponse.SC_OK)
.setAccessToken(accessToken)
.buildJSONMessage();
}
//根據OAuthResponse生成ResponseEntity
return new ResponseEntity<String>(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();
}
return null;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
上面的程式碼對應上圖的步驟4,驗證客戶端的授權碼,並返回accessToken。

/**
*
* @ClassName: UserInfoController
* @Description: 根據客戶端的accessToken來返回使用者資訊到客戶端
* @author aiqinhai
* @date 2018年5月24
*/
@Controller
public class UserInfoController {
@RequestMapping("/userInfo")
public HttpEntity<String> userInfo(HttpServletRequest request)
throws OAuthSystemException{
try {
//獲取客戶端傳來的OAuth資源請求
OAuthAccessResourceRequest oauthRequest = new
OAuthAccessResourceRequest(request, ParameterStyle.QUERY);
//獲取Access Token
String accessToken = oauthRequest.getAccessToken();
System.out.println("從客戶端獲取的accessToken----"+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<String>(headers, HttpStatus.UNAUTHORIZED);
}
//這裡沒有從資料庫查詢了,簡單指定為"aiqinhai"
String username="aiqinhai";
return new ResponseEntity<String>(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<String>(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));
return new ResponseEntity<String>(HttpStatus.BAD_REQUEST);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
上段程式碼對應上圖中的步驟6,驗證accessToken,返回使用者請求資源,這裡簡單用username來模擬使用者請求的資源。
服務端控制檯輸出如下


相關依賴jar包
客戶端依賴jar包

<dependency>
<groupId>org.apache.oltu.oauth2</groupId>
<artifactId>org.apache.oltu.oauth2.client</artifactId>
<version>0.31</version>
</dependency>
1
2
3
4
5
服務端依賴jar包

<dependency>
<groupId>org.apache.oltu.oauth2</groupId>
<artifactId>org.apache.oltu.oauth2.authzserver</artifactId>
<version>0.31</version>
</dependency>
<dependency>
<groupId>org.apache.oltu.oauth2</groupId>
<artifactId>org.apache.oltu.oauth2.resourceserver</artifactId>
<version>0.31</version>
</dependency>
---------------------
作者:愛琴孩
來源:CSDN
原文:https://blog.csdn.net/qq_28165595/article/details/80459185
版權宣告:本文為博主原創文章,轉載請附上博文連結!