JWT应用接入
在CCP控制台上,开发者可以创建出一个域(Domain)。
域:拥有独立的访问入口、资源空间、用户体系等。
CCP为每个域提供一套独立的用户体系。
- 支持OAuth2.0应用接入: 目前支持基于钉钉和RAM子用户的OAuth登录接入。
- 支持JWT应用接入:支持已有的用户体系的接入,比如已有的web服务想要增加云盘的功能等。
JWT应用介绍
此类应用可以通过私钥计算出一个JWT(JSON Web Token),该JWT具有访问已经配置了公钥的服务端的API的能力(权限)。
JWT应用,适合服务端应用访问CCP的数据,比如企业通过自建应用访问企业的数据(数据所有权属于企业)的场景,这个场景不需要最终用户参与授权。
适用场景
适用场景1: 企业A已有独立的账号体系和登录入口,想要使用已有的登录入口结合CCP搭建一套已有独立账号的云存储系统。
适合场景2: 企业A开发一个运维统计应用,用来定期统计一些数据指标。
JWT 应用原理
- 需要生成一对公私钥。
- 应用服务端配置私钥,CCP API端配置公钥。
- 应用服务端可以使用私钥计算出一个JWT Token,这个JWT具有一定的权限,可以直接调用CCP API相应的接口。
目前使用最广泛的场景,就是调用CCP API的GetToken接口,获取任意用户的AccessToken。非常适合已有用户体系接入。
下面介绍详细的接入步骤。
接入步骤概览
- 租户在CCP控制台创建一个JWT应用。
- 然后生成一对公私钥。公钥保存到CCP服务端,私钥自己复制保存。
- 使用我们提供的SDK可以通过私钥生成一个有特定权限的并且有时效的JWT。
- 使用该JWT调用getToken接口换取一个代表用户身份的AccessToken。
详细步骤
(1) 创建域
(2) 创建应用
进入域详情,在应用列表界面,创建一个应用:
(3) 设置公钥
应用创建好后,点击”设置公钥”:
生成公私钥:
生成公私钥后,记得复制私钥,自己保存。然后点确定即可。
(4) 服务端计算JWT
需要开发代码。
逻辑在用户登录成功之后,通过私钥计算出JWT。 具体的计算方法:
node.js 参考代码:
const JWT = require('jsonwebtoken');
const privateKeyPEM = '';
var current_time_sec = Math.floor(Date.now()/1000);
var opt = {
iss:'',
sub:'',
sub_type:'',
aud:'',
jti: '',
exp: current_time_sec + 60,
iat: current_time_sec ,
//nbf: '',
auto_create: true,
};
var token = JWT.sign(opt, privateKeyPEM, {
algorithm: 'RS256'
});
opt 参数说明:
字段名 | 是否必选 | 类型 | 描述 |
---|---|---|---|
iss | 必选 | String | App ID |
sub | 必选 | String | User ID、Domain ID |
sub_type(扩展字段) | 必选 | String | 账号类型,目前支持填 user、service,此处填user,则sub为userID,签发普通用户accessToken。 此处填service,则sub为domainID,签发domain服务账号accessToken(超级管理员权限) |
aud | 必选 | String | Domain ID |
jti | 必选 | String | 应用生成JWT的唯一标识,长度16-128位,推荐使用uuid即可 |
exp | 必选 | Integer | JWT过期时间, Unix Time,单位秒,最多在当前时间基础上加60秒 |
iat | 可选 | Integer | 签发时间,Unix Time,单位秒,在此时间之前无法使用,如:1577682075 |
nbf | 可选 | Integer | 生效时间,Unix Time,单位秒,不指定则默认生效 |
auto_create(扩展字段) | 可选 | Boolean | 如果用户不存在,则自动创建,默认不创建用户。 |
(5) 通过JWT换取任意用户的AccessToken
调用CCP API换取。
POST /v2/oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&client_id=${APP_ID}&assertion=xxxxxxxxxx
请求参数说明:
字段名 | 是否必选 | 类型 | 描述 |
---|---|---|---|
grant_type | 必选 | String | 申请授权的类型,此处应为字符串常量: urn:ietf:params:oauth:grant-type:jwt-bearer |
client_id | 必选 | String | 应用ID |
assertion | 必选 | String | 上一步骤计算出来的JWT |
返回 token json 样例:
{
access_token: 'eyJh****eQdnUTsEk4',
refresh_token: 'kL***Lt',
expires_in: 7200,
token_type: 'Bearer'
}
浏览器端拿到用户的AccessToken后,就可以直接调用CCP API了。
(6) 使用 Basic UI (可选)
如果您不想自己开发UI,而我们官方提供的Basic UI可以满足您的要求,可以直接使用Basic UI。
原理: 使用window.open 打开 basic ui,postMessage传递AccessToken过去即可。
示例代码:
const ENDPOINT = `https://${domain_id}.apps.alicloudccp.com`
window.addEventListener('message', onMessage, false)
var win = window.open(ENDPOINT + '/accesstoken')
async function onMessage(e) {
if (e.data.code == 'token' && e.data.message == 'ready') {
var result = await getToken();// 从服务端获取 AccessToken
//result = {"access_token": ...}
win.postMessage({
code: 'token',
message: result
}, '*')
window.removeEventListener('message', onMess)
}
}
附录:
服务端获取AccessToken 的 Node.js 代码实现:
const fs = require('fs')
const JWT = require('jsonwebtoken');
const axios = require('axios')
init()
async function init() {
try {
//这几个变量需要根据实际情况填写
var params = {
domain_id: '${DOMAIN_ID}',
client_id: '${APP_ID}',
user_id: '${USER_ID}',
privateKeyPEM: "${PRIVATE_KEY_PEM}"
};
var obj = await JWTGetUserToken(params)
var tokenInfo = obj.data
console.log(tokenInfo)
} catch (e) {
if (e.response) {
console.log(e.response.status)
console.log(e.response.headers)
console.log(e.response.data)
} else {
console.log(e)
}
}
}
async function JWTGetUserToken({ domain_id, client_id, user_id, privateKeyPEM }) {
var now_sec = parseInt(Date.now()/1000)
var opt = {
iss: client_id,
sub: user_id,
sub_type: 'user',
aud: domain_id,
jti: Math.random().toString(36).substring(2),
exp: now_sec + 60,
// iat: now_sec,
// nbf: '',
auto_create: true,
};
var token = JWT.sign(opt, privateKeyPEM, {
algorithm: 'RS256'
});
const PRE = `https://${domain_id}.api.alicloudccp.com`
return await axios({
method: 'post',
url: PRE + '/v2/oauth/token',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
data: params({
grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
client_id: client_id,
assertion: token
})
})
}
function params(m){
const params = new URLSearchParams();
for(var k in m){
params.append(k, m[k]);
}
return params;
}
版权声明
本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。
评论