OAuth對接實踐 - Linux應用
本章結合Demo代碼,介紹單租戶托管型應用免登及用戶信息獲取的相關流程。開發之前,請務必參考詳細的對接專題文檔,以便對OAuth對接有全面的了解。注:本Demo代碼,基于Springboot框架開發,下載鏈接請參考文章底部的“示例Demo”。
1 獲取oauthcode
根據環境變量獲取到的appkey與請求頭獲取跳轉地址拼接鑒權URL并訪問該URL。示例代碼如下:
//-----要先進行部署上線獲取到appkey和appSecret-------//
private static Logger logger = LoggerFactory.getLogger(Oauth2Controller.class);
/**
* 注意: //-----要先進行部署上線獲取到appkey和appSecret-------
* //環境變量獲取appkey和appSecret也可能為iot_hosting_appKey和iot_hosting_appSecret;需要和終端查看的保持一致
*/
public static final String OAUTH_CLIENT_ID = System.getenv("iot.hosting.appKey");
public static final String OAUTH_CLIENT_SECRET = System.getenv("iot.hosting.appSecret");
private static String response_type = "code";
private static String redirectUrlPage = "\"http://\" + request.getHeader(\"Host\")";//是跳轉自己系統應用的訪問入口,可通過請求頭獲取
public static final String OAUTH_CLIENT_AUTHORIZE = System.getenv("iot.host.oauth.domain");
public static final String REDIRECT_URL = System.getenv("iot.hosting.api.domain");
/**
* 第一次請求:返回為callback地址和code值
* <p>
* 拼接示例:https://account.iot.aliyun.com/oauth2/auth?&&redirect_uri=http://47.95.191.3:8***&client_id=2768****&response_type=code
*
* @throws Exception
*/
@RequestMapping("/redirectToRequestAuthorizationCodeURL")
public String redirectToRequestAuthorizationCodeURL(HttpServletRequest request) throws Exception {
// accessTokenRequest 是用來描述請求對象的,描述了請求地址,和請求參數
OAuthClientRequest accessTokenRequest = OAuthClientRequest.authorizationLocation(OAUTH_CLIENT_AUTHORIZE)
.setResponseType(response_type).setClientId(OAUTH_CLIENT_ID).setRedirectURI(redirectUrlPage).buildQueryMessage();
return "redirect:" + accessTokenRequest.getLocationUri();
}
鑒權URL會連接到IoT平臺進行相關驗證,成功后會根據{ redirectUrl }中的地址進行跳轉并攜帶code參數。該參數就是我們后續用到OAuthCode參數。示例代碼如下:
http://39.97.129.***:****/?code=b27baa5b367baf46d6625989cadc87e7
??注意格式為:請求頭(http)+外部暴露的端口IP+請求appkey后獲取的返回code值。
另外,一般我們的應用入口是登錄頁面與OAuth免登中的回調跳轉地址共用一個地址,所以可以通過是否有code參數判斷是否是OAuth回調跳轉,原有的登錄頁面也應該保留。
/**
* 返回授權碼
*
* @param request
* @return
* @throws Exception
*/
@RequestMapping("/getAuthorizationCode")
public Object getAuthorizationCode(HttpServletRequest request) throws Exception {
OAuthAuthzRequest oauthRequest = new OAuthAuthzRequest(request);
String redirectURI = oauthRequest.getParam(OAuth.OAUTH_REDIRECT_URI);
String authorizationCode = oauthRequest.getParam(OAuth.OAUTH_CODE);
//把 state 寫到一個 重定向的響應
OAuthASResponse.OAuthAuthorizationResponseBuilder builder = OAuthASResponse.authorizationResponse(request, HttpServletResponse.SC_FOUND);
builder.setCode(authorizationCode);
OAuthResponse response = builder.location(redirectURI).buildQueryMessage();
return "redirect:" + response.getLocationUri();
}
2 獲取access_token
在調用getAccessTokenByAuthCode接口獲取access_token。示例代碼如下:
/**
* 發送請求返回
* 根據authcode來獲取accesstoken
* <p>
* api: getAccessTokenByAuthCode
*
* @param request
* @return
* @throws Exception
*/
@RequestMapping("/getAccessTokenByAuthCode")
public Object getAccessTokenByAuthCode(HttpServletRequest request) throws Exception {
String code = "835d5af7a835239a9566a1f9078d83a0";//測試使用 request.getHeader("code")
IoTApiClientBuilderParams IoTApiClientBuilderParams =
new IoTApiClientBuilderParams();
IoTApiClientBuilderParams.setAppKey("2776****");
IoTApiClientBuilderParams.setAppSecret("9ca6b2b12aa35b4549659b9****");
SyncApiClient syncClient = new SyncApiClient(IoTApiClientBuilderParams);
IoTApiRequest request1 = new IoTApiRequest();
//設置api的版本
request1.setApiVer("1.0.1");
request1.putParam("code", code);
request1.putParam("grant_type", "code");
request1.putParam("redirect_uri", "http://39.97.129.***:****");
request1.putParam("client_id", "2776****");
//請求參數域名、path、request
ApiResponse response = syncClient.postBody(REDIRECT_URL,
"/user/oauth2/token/get", request1, true);
System.out.println("response code = " + response.getCode()
+ " response = " + new String(response.getBody(), "UTF-8"));
return "redirect:requestResourcePage?accessToken=" + response.getMessage();
}
3 獲取用戶信息
在調用getUserInfoByAccessToken接口獲取access_token。示例代碼如下:
/**
* 發送請求返回
* oauth2的授權,根據accesstoken獲取用戶信息
* <p>
* api: getUserInfoByAccessToken
*
* @param
* @return
* @throws Exception
*/
@RequestMapping("/getUserInfoByAccessToken")
public Object getUserInfoByAccessToken() throws Exception {
String token = "e171cd3d7c71ed189afb8ef5950adb58";
IoTApiClientBuilderParams IoTApiClientBuilderParams =
new IoTApiClientBuilderParams();
IoTApiClientBuilderParams.setAppKey("2776****");
IoTApiClientBuilderParams.setAppSecret("9ca6b2b12aa35b4549659b9****");
SyncApiClient syncClient = new SyncApiClient(IoTApiClientBuilderParams);
IoTApiRequest request1 = new IoTApiRequest();
//設置api的版本
request1.setApiVer("1.0.2");
request1.putParam("access_token", token);
//請求參數域名、path、request
ApiResponse response = syncClient.postBody(REDIRECT_URL,
"/user/oauth2/userinfo/get", request1, true);
System.out.println("response code = " + response.getCode()
+ " response = " + new String(response.getBody(), "UTF-8"));
return "redirect:requestResourcePage?userInfo=" + response.getMessage();
}
4 實現免登
按照上面操作完成后,系統會按照這個邏輯判斷用戶是否需要免登,我們拿到了IoT平臺用戶的相關信息,在系統應用中就可以判斷該用戶是否存在,是否是第一次登入系統等,來實現免登邏輯:a、如果用戶是首次登錄,則可以根據獲取到的IoT用戶信息在系統內創建賬號密碼與初始化賬戶相關的信息。b、如果用戶是首次登錄且需要收集用戶額外的信息,比如所屬企業信息,還可以展示一個收集信息的頁面,收集信息后再創建用戶賬戶信息。c、如果用戶是首次登錄,可以創建隨機的,讓用戶登入系統后提示其再修改密碼。也可以計算一個一段時間內有效的sign簽名實現免登。
5 示例Demo
下載地址:OAuth Demo for Linux