本文為您介紹了三方賬號授權的操作流程。
免登流程
- 第三方系統的用戶在己方賬號系統登錄成功,獲取用戶登錄狀態。
- 第三方系統為用戶根據約定規則生成JWT Token。
- 第三方系統以JWT Token請求免登接口,獲取Fuyun門戶系統access token。
- 第三方系統以上述access token請求前端JS-SDK。說明
- Fuyun:智能聯絡中心產品開放平臺。
- IDP:Identity provider(身份提供者)。
三方賬號免登開發列表
- 在第三方賬號系統登錄成功后,生成JWT token(JWT生成規則)。
- 調用Fuyun IDP免登接口獲取Fuyun access token(免登接口)。
JWT token生成規則
payload包含字段
字段 | 描述 | 示例 |
---|---|---|
iss | 簽發者網站域名 | "iss":"http://signin.rhino****.com" |
exp | 過期時間戳 | |
user_name | JWT token頒發給的用戶,此user_name用來映射唯一坐席 | |
jti | 隨機uuid | "b774ef13-a5bc-****-8346-042d879efb1a" |
JWT token加密
- JWT token的加密方式采用RS256方式加簽,public key需要在注冊IDP Client的時候提供,private key請您妥善保管。
- private key與public key生成過程可參考下文使用OpenSSL生成密鑰對,或者采用三方賬號自己的方式生成。
三方賬號免登Fuyun門戶接口
說明 此處獲取的access_token可用于JS_SDK初始化授權。
1、token置換接口
請求URL
- URL:https://signin.rhinokeen.com/oauth/token_exchange。
- 請求類型:POST。
請求HEADER
字段 | 示例 | 描述 |
---|---|---|
Authorization | "Authorization: Basic YWxpYmFiYS14aWFvZXI6YmNlMTllZDYtYTFhNC00NzA3LTgwZjAtYTM4OGY3MGUxNWQ3" | 授權類型,接口使用http basic authentication認證方式
Authorization= Basic Base64.encode(client_id:client_secret) |
請求參數
字段 | 示例 | 描述 |
---|---|---|
grant_type | "urn:ietf:params:oauth:grant-type:token-exchange" | 授權類型 |
scope | "fuyun-dev" | 訪問范圍 |
redirect_url | "http://****.com/callback" | 回調地址 |
subject_token | 第三方JWT token | |
subject_issuer | "http://****.com" | 簽發者網站域名 |
成功返回示例
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwOi8vZGV2ZWxvcGVyLnJoaW5va2Vlbi5jb20iLCJleHAiOjE1OTk3OTczNjMsInVzZXJfbmFtZSI6IumjkuWymiIsImp0aSI6ImI3NzRlZjEzLWE1YmMtNGM3Yi04MzQ2LTA0MmQ4NzllZmIxYSIsImNsaWVudF9pZCI6ImRpbmdkaW5nIiwic2NvcGUiOlsiZnV5dW4tZGV2Il19.jAEBjO9N0D6vjTA0tx8uiAh5dzDgSpo-LVHBmDIMnGVRSvJQWvEc3r6zrp2bRbK7pv83aouhSarHIhtUZ4O-utxP6vMAsGheQstNrXHk79J1XkK-UEXXJXznEyqJvgqjtRw8dTUA2PKSM-1CjRgdRDLvcD7kUGCTAFyYnHwrtdeDw6Vkq1IvkQ3jo4mlTa5pYjF_trXUdAil09IDYk4HNzKHYmuWaAKko42w7abv0GjF7LkNQWM4g6NY3otyge7kxkSHT8K4pOlD7O0zqZlRWfaUXjfGY6H3gdDeRU5N3NyyUXBt2I4VM7pZsW-qwR0XjacdasV5J8UObP37_WzEEw",
"token_type": "bearer",
"refresh_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiLpo5LlspoiLCJzY29wZSI6WyJmdXl1bi1kZXYiXSwiYXRpIjoiYjc3NGVmMTMtYTViYy00YzdiLTgzNDYtMDQyZDg3OWVmYjFhIiwiaXNzIjoiaHR0cDovL2RldmVsb3Blci5yaGlub2tlZW4uY29tIiwiZXhwIjoxNTk5ODQ0MTU5LCJqdGkiOiJjOTQ5N2ExMi1kZWE5LTRhYmYtOTgxYS0xYjQ1MTRkZWI2MDUiLCJjbGllbnRfaWQiOiJkaW5nZGluZyJ9.NlZ0ay2u0KcxUbgSnacoFw9YwVUJ6cOqwS_vhO92klZroedKzii3vw2rYzbDhTJQshaRgDdAtL2HVrI0bkuWB-T0IuLd_QEnpcDRujqjovxKKJN-uQack5GEd8AwBKYG67IiSGUztIn-RNXO9wGNPM18gQKACc8E34JRbgXnZL6sR6651_pJNT5LpItDe4juDHPgmLpNOHl5Um7wUiE0PpR21d9atJPy5Kt4LL4b4Tnbbtexhofg_vxWVqebNlh-2-nKJyryaKV9otlP0BEh21K-0MFVRotIuAVOwN7goObG6x5KEKFBI8lxI0s9An38TqQzJ1LvzIh77XG7wIDzFg",
"expires_in": 3599,
"scope": "fuyun-dev",
"iss": "http://developer.rhinokeen.com",
"jti": "b774ef13-a5bc-4c7b-8346-042d879efb1a"
}
錯誤返回示例
{
"error": "invalid_grant",
"error_description": "Invalid refresh token: 1631958c-df3a-4acd-ac1f-829bcbb6caf01"
}
2、token刷新接口
請求信息
- URL:https://signin.rhinokeen.com/oauth/token。
- 請求類型:GET
請求HEADER
字段 | 示例 | 描述 |
---|---|---|
Authorization | "Authorization: Basic YWxpYmFiYS14aWFvZXI6YmNlMTllZDYtYTFhNC00NzA3LTgwZjAtYTM4OGY3MGUxNWQ3" | 授權類型,接口使用http basic authentication認證方式。
Authorization= Basic Base64.encode(client_id:client_secret) |
請求參數
字段 | 示例 | 描述 |
---|---|---|
grant_type | "refresh_token" | 授權類型 |
refresh_token | token_exchange獲取的refresh_token | refresh_token |
成功返回示例
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwOi8vZGV2ZWxvcGVyLnJoaW5va2Vlbi5jb20iLCJleHAiOjE1OTk3OTczNjMsInVzZXJfbmFtZSI6IumjkuWymiIsImp0aSI6ImI3NzRlZjEzLWE1YmMtNGM3Yi04MzQ2LTA0MmQ4NzllZmIxYSIsImNsaWVudF9pZCI6ImRpbmdkaW5nIiwic2NvcGUiOlsiZnV5dW4tZGV2Il19.jAEBjO9N0D6vjTA0tx8uiAh5dzDgSpo-LVHBmDIMnGVRSvJQWvEc3r6zrp2bRbK7pv83aouhSarHIhtUZ4O-utxP6vMAsGheQstNrXHk79J1XkK-UEXXJXznEyqJvgqjtRw8dTUA2PKSM-1CjRgdRDLvcD7kUGCTAFyYnHwrtdeDw6Vkq1IvkQ3jo4mlTa5pYjF_trXUdAil09IDYk4HNzKHYmuWaAKko42w7abv0GjF7LkNQWM4g6NY3otyge7kxkSHT8K4pOlD7O0zqZlRWfaUXjfGY6H3gdDeRU5N3NyyUXBt2I4VM7pZsW-qwR0XjacdasV5J8UObP37_WzEEw",
"token_type": "bearer",
"refresh_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiLpo5LlspoiLCJzY29wZSI6WyJmdXl1bi1kZXYiXSwiYXRpIjoiYjc3NGVmMTMtYTViYy00YzdiLTgzNDYtMDQyZDg3OWVmYjFhIiwiaXNzIjoiaHR0cDovL2RldmVsb3Blci5yaGlub2tlZW4uY29tIiwiZXhwIjoxNTk5ODQ0MTU5LCJqdGkiOiJjOTQ5N2ExMi1kZWE5LTRhYmYtOTgxYS0xYjQ1MTRkZWI2MDUiLCJjbGllbnRfaWQiOiJkaW5nZGluZyJ9.NlZ0ay2u0KcxUbgSnacoFw9YwVUJ6cOqwS_vhO92klZroedKzii3vw2rYzbDhTJQshaRgDdAtL2HVrI0bkuWB-T0IuLd_QEnpcDRujqjovxKKJN-uQack5GEd8AwBKYG67IiSGUztIn-RNXO9wGNPM18gQKACc8E34JRbgXnZL6sR6651_pJNT5LpItDe4juDHPgmLpNOHl5Um7wUiE0PpR21d9atJPy5Kt4LL4b4Tnbbtexhofg_vxWVqebNlh-2-nKJyryaKV9otlP0BEh21K-0MFVRotIuAVOwN7goObG6x5KEKFBI8lxI0s9An38TqQzJ1LvzIh77XG7wIDzFg",
"expires_in": 3599,
"scope": "fuyun-dev",
"iss": "http://developer.rhinokeen.com",
"jti": "b774ef13-a5bc-4c7b-8346-042d879efb1a"
}
錯誤返回示例
{
"error": "invalid_grant",
"error_description": "Invalid refresh token: 1631958c-df3a-4acd-ac1f-829bcbb6caf01"
}
使用OpenSSL生成密鑰對
生成RSA密鑰
首先進入OpenSSL工具,輸入以下命令:
OpenSSL> genrsa -out app_private_key.pem 2048 #生成私鑰
OpenSSL> pkcs8 -topk8 -inform PEM -in app_private_key.pem -outform PEM -nocrypt -out app_private_key_pkcs8.pem #Java開發者需要將私鑰轉換成PKCS8格式
OpenSSL> rsa -in app_private_key.pem -pubout -out app_public_key.pem #生成公鑰
OpenSSL> exit #退出OpenSSL程序
經過以上步驟,開發者可以在當前文件夾中(OpenSSL運行文件夾),看到 app_private_key.pem(開發者RSA私鑰,非 Java 語言適用)、app_private_key_pkcs8.pem(pkcs8格式開發者RSA私鑰,Java語言適用)和app_public_key.pem(開發者RSA公鑰)3個文件。開發者將私鑰保留,將公鑰提交配置到開放平臺,用于驗證簽名。以下為私鑰文件和公鑰文件示例。
說明 對于使用Java的開發者,需將生成的pkcs8格式的私鑰去除頭尾、換行和空格,作為私鑰填入代碼中,對于.NET和PHP的開發者來說,無需進行pkcs8命令行操作。
標準的私鑰文件示例(PHP、.NET使用)
-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQC+L0rfjLl3neHleNMOsYTW8r0QXZ5RVb2p/vvY3fJNNugvJ7lo4+fdBz+LN4mDxTz4MTOhi5e2yeAqx+v3nKpNmPzC5LmDjhHZURhwbqFtIpZD51mOfno2c3MDwlrsVi6mTypbNu4uaQzw/TOpwufSLWF7k6p2pLoVmmqJzQiD0QIDAQABAoGAakB1risquv9D4zX7hCv9MTFwGyKSfpJOYhkIjwKAik7wrNeeqFEbisqv35FpjGq3Q1oJpGkem4pxaLVEyZOHONefZ9MGVChT/MNH5b0FJYWl392RZy8KCdq376Vt4gKVlABvaV1DkapL+nLh7LMo/bENudARsxD55IGObMU19lkCQQDwHmzWPMHfc3kdY6AqiLrOss+MVIAhQqZOHhDe0aW2gZtwiWeYK1wB/fRxJ5esk1sScOWgzvCN/oGJLhU3kipHAkEAysNoSdG2oWADxlIt4W9kUiiiqNgimHGMHPwp4JMxupHMTm7D9XtGUIiDijZxunHv3kvktNfWj3Yji0661zHVJwJBAM8TDf077F4NsVc9AXVs8N0sq3xzqwQD/HPFzfq6hdR8tVY5yRMb4X7+SX4EDPORKKsgnYcur5lk8MUi7r072iUCQQC8xQvUne+fcdpRyrR4StJlQvucogwjTKMbYRBDygXkIlTJOIorgudFlrKP/HwJDoY4uQNl8gQJb/1LdrKwIe7FAkBl0TNtfodGrDXBHwBgtN/t3pyi+sz7OpJdUklKE7zMSBuLd1E3O4JMzvWP9wEE7JDb+brjgK4/cxxUHUTkk592
-----END RSA PRIVATE KEY-----
pkcs8處理后的私鑰文件示例(Java使用)
MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAN0yqPkLXlnhM+2H/57aHsYHaHXazr9pFQun907TMvmbR04wHChVsKVgGUF1hC0FN9hfeYT5v2SXg1WJSg2tSgk7F29SpsF0I36oSLCIszxdu7ClO7c22mxEVuCjmYpJdqb6XweAZzv4Is661jXP4PdrCTHRdVTU5zR9xUByiLSVAgMBAAECgYEAhznORRonHylm9oKaygEsqQGkYdBXbnsOS6busLi6xA+iovEUdbAVIrTCG9t854z2HAgaISoRUKyztJoOtJfI1wJaQU+XL+U3JIh4jmNx/k5UzJijfvfpT7Cv3ueMtqyAGBJrkLvXjiS7O5ylaCGuB0Qz711bWGkRrVoosPM3N6ECQQD8hVQUgnHEVHZYtvFqfcoq2g/onPbSqyjdrRu35a7PvgDAZx69Mr/XggGNTgT3jJn7+2XmiGkHM1fd1Ob/3uAdAkEA4D7aE3ZgXG/PQqlm3VbE/+4MvNl8xhjqOkByBOY2ZFfWKhlRziLEPSSAh16xEJ79WgY9iti+guLRAMravGrs2QJBAOmKWYeaWKNNxiIoF7/4VDgrcpkcSf3uRB44UjFSn8kLnWBUPo6WV+x1FQBdjqRviZ4NFGIP+KqrJnFHzNgJhVUCQFzCAukMDV4PLfeQJSmna8PFz2UKva8fvTutTryyEYu+PauaX5laDjyQbc4RIEMU0Q29CRX3BA8WDYg7YPGRdTkCQQCG+pjU2FB17ZLuKRlKEdtXNV6zQFTmFc1TKhlsDTtCkWs/xwkoCfZKstuV3Uc5J4BNJDkQOGm38pDRPcUDUh2/
公鑰文件示例
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDQWiDVZ7XYxa4CQsZoB3n7bfxLDkeGKjyQPt2FUtm4TWX9OYrd523iw6UUqnQ+Evfw88JgRnhyXadp+vnPKP7unormYQAfsM/CxzrfMoVdtwSiGtIJB4pfyRXjA+KL8nIa2hdQy5nLfgPVGZN4WidfUY/QpkddCVXnZ4bAUaQjXQIDAQAB
-----END PUBLIC KEY-----
附錄
JWT token生成代碼demo
// pom依賴
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-jwt</artifactId>
<version>1.1.1.RELEASE</version>
</dependency>
/**
* 生成jwtToken
* @return
*/
public static String generateToken(String userName, String iss, long expireTime, String privateKeyStr) {
try {
privateKeyStr = privateKeyStr.replaceAll("\\s+", "");
byte[] decodedPrivateKey = Base64.getDecoder().decode(privateKeyStr.getBytes());
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(decodedPrivateKey);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(spec);
RsaSigner signer = new RsaSigner((RSAPrivateKey) privateKey);
// generate token
Map<String, Object> payloadMap = new HashMap<>(4);
payloadMap.put("iss", iss);
payloadMap.put("jti", UUID.randomUUID().toString());
payloadMap.put("user_name", userName);
payloadMap.put("exp", expireTime);
return JwtHelper.encode(new JSONObject(payloadMap).toJSONString(), signer).getEncoded();
} catch (InvalidKeySpecException | NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}