# oauth手册
⽂档版本 | 内容修订 | 修订⼈ | 修订⽇期 |
---|---|---|---|
V1.0 | 初稿 | 郭程豪 | 2023-08-01 |
# 目录
# 注册服务
登陆用户认证平台(https://id.sansi.net)企业用户使用企业微信扫码登陆,其他用户联系管理员注册
# 判断中控是否开启用户认证
从环境变量中获取SANSI_ACCOUNT_AUTH=http://192.168.31.66:3500
变量,如果有值,说明中控已开启了用户认证,需要对请求中的token进行校验
const SANSI_ACCOUNT_AUTH = process.env.SANSI_ACCOUNT_AUTH;
# 接入方式-授权码模式
# 1. 引导用户登陆
重定向页面,第三方应用将页面重定向至用户认证平台登陆页,clientId需提前在用户认证平台注册获取
http://192.168.31.66:3500/login?response_type=code&client_id=ebcfba346a9844ccace356aeb186a826&redirect_uri=http://192.168.158.75:3436&scope=admin,user&state=47298951f14a75110b8fe1
参数名 | 参数值 | 是否必填 | 参数类型 | 描述说明 |
---|---|---|---|---|
response_type | code | 是 | String | 返回类型,固定为code |
client_id | ebcfba346a9844ccace356aeb186a826 | 是 | String | client_id |
redirect_uri | http://192.168.158.75:3436 | 是 | String | 回调地址 |
scope | admin,user | 否 | String | 范围 |
state | abcde | 否 | String | 唯一性随机码 |
# 2. 同意授权后,返回code(无需对接)
用户登陆成功后,点击同意授权,页面重定向至 redirect_uri
- 接口URL: POST http://192.168.31.66:3500/account/api/v1/oauth/authorize
- Content-Type: multipart/form-data
- 认证方式: 无需认证
参数名 | 参数值 | 是否必填 | 参数类型 | 描述说明 |
---|---|---|---|---|
response_type | code | 是 | String | 返回类型,固定为code |
client_id | a17446eb12264007ae735ecbd79ffb6c | 是 | String | client_id |
redirect_uri | http://192.168.158.75:3436 | 是 | String | 回调地址 |
scope | admin,user | 否 | String | 范围 |
state | abcde | 否 | String | 唯一性随机码 |
- 回调示例
http://192.168.158.75:3436?code=MZGWNJLKMMITNJNLYY0ZZTA1LTLLZJITMWFHMJI3ZGYYZTVJ&state=47298951f14a75110b8fe1
跳转页面如下
# 3. code换取token
用户认证平台通过回调地址redirect_uri将用户授权码(code)传递给应用服务器或者直接在Webview中,应用服务器使用code换取token
- 接口URL: POST http://192.168.31.66:3500/account/api/v1/oauth/token
- Content-Type: multipart/form-data
- 认证方式: 无需认证
请求示例
import axios from "axios";
const form = new FormData();
form.append("grant_type", "authorization_code");
form.append("client_id", "a17446eb12264007ae735ecbd79ffb6c");
form.append("client_secret", "fca40b86c56548a6ba37db0a8be31a881011ea6f22424cc7850221fc3c92a682cc981df3ec9545bebdcfb188fff2358fa9338db1b8544a0b9c71a8f8529b8031");
form.append("redirect_uri", "http://localhost:3436");
form.append("code", "YJA2MTZJODKTZWM3NI0ZOTIXLTG5ZJMTZDFLZJU0YME1M2ZL");
const options = {
method: 'POST',
url: 'http://192.168.31.66:3500/account/api/v1/oauth/token',
headers: {
lang: 'zh-CN',
'content-type': 'multipart/form-data'
},
data: form
};
axios.request(options).then(function (response) {
console.log(response.data);
}).catch(function (error) {
console.error(error);
});
参数名 | 参数值 | 是否必填 | 参数类型 | 描述说明 |
---|---|---|---|---|
grant_type | authorization_code | 是 | String | 固定值 |
client_id | a17446eb12264007ae735ecbd79ffb6c | 是 | String | clientId |
client_secret | fca40b86c56548a6ba37db0a8be31a881011ea6f224 | 是 | String | clientSecret |
redirect_uri | http://localhost:3469/kl/api/v1/oauth/callback | 是 | String | 回调地址 |
code | YJA2MTZJODKTZWM3NI0ZOTIXLTG5ZJMTZDFLZJU0YME1M2ZL | 是 | String | 授权码(有效期5分钟) |
返回示例
{
"access_token": "NMRIZDLHNMYTNZI2NS0ZMDMZLTHHNJQTNGNJNWYWZMQ1ZGYY",
"expires_in": 7200,
"refresh_token": "NTK5NDY2ZWMTMDGWMC01ZWY3LWJJMJCTZTK5YTBMMMJKNDMX",
"scope": "admin",
"token_type": "Bearer"
}
# 接入方式-密码授权模式
代理用户密码登陆,用户应用中输入帐号密码,应用代替用户登陆(服务端请求)
- 接口URL: POST http://192.168.31.66:3500/account/api/v1/oauth/token
- Content-Type: multipart/form-data
- 认证方式: 无需认证
请求示例
import axios from "axios";
const form = new FormData();
form.append("grant_type", "password");
form.append("client_id", "ebcfba346a9844ccace356aeb186a826");
form.append("client_secret", "d80d5182071d43eeac45598ab89a99797a49deb55dec4b4aa009daba01bace27ec77f015abb9435b8c17edb2f06ec62049c0321280fa415689899eed0a385d45");
form.append("username", "xxxxx");
form.append("password", "xxxxx");
const options = {
method: 'POST',
url: 'http://192.168.31.66:3500/account/api/v1/oauth/token',
headers: {
lang: 'zh-CN',
'content-type': 'multipart/form-data'
},
data: form
};
axios.request(options).then(function (response) {
console.log(response.data);
}).catch(function (error) {
console.error(error);
});
参数名 | 参数值 | 是否必填 | 参数类型 | 描述说明 |
---|---|---|---|---|
grant_type | password | 是 | String | 返回类型,固定为code |
client_id | ebcfba346a9844ccace356aeb186a826 | 是 | String | client_id |
client_secret | d80d5182071d43eeac45598ab... | 是 | String | clientSecret |
username | 018470 | 是 | String | 账户 |
password | 123456 | 是 | String | 密码 |
返回示例
{
"access_token": "ZWFMYMZJNGITOTLINY0ZMGMYLTKZM2ITMTFIYTI3ZDUXNDLI",
"expires_in": 7200,
"refresh_token": "ODQXMWQ2YTATYZQXYY01OTU4LTKZMTMTYWJIM2ZHZWVHZGFK",
"token_type": "Bearer"
}
# 刷新token
用户应用中输入帐号密码,应用代替用户登陆(服务端请求)
- 接口URL: POST http://192.168.31.66:3500/account/api/v1/oauth/token
- Content-Type: multipart/form-data
- 认证方式: 无需认证
请求示例
import axios from "axios";
const form = new FormData();
form.append("grant_type", "refresh_token");
form.append("client_id", "ebcfba346a9844ccace356aeb186a826");
form.append("client_secret", "d80d5182071d43eeac45598ab89a99797a49deb55dec4b4aa009daba01bace27ec77f015abb9435b8c17edb2f06ec62049c0321280fa415689899eed0a385d45");
form.append("refresh_token", "OGQ5N2NHNWYTMDG3NC01M2ZLLTG1ZDCTZJCYZTA5MMYWYTC3");
const options = {
method: 'POST',
url: 'http://192.168.31.66:3500/account/api/v1/oauth/token',
headers: {
lang: 'zh-CN',
'content-type': 'multipart/form-data'
},
data: form
};
axios.request(options).then(function (response) {
console.log(response.data);
}).catch(function (error) {
console.error(error);
});
参数名 | 参数值 | 是否必填 | 参数类型 | 描述说明 |
---|---|---|---|---|
grant_type | refresh_token | 是 | String | 返回类型,固定为code |
client_id | ebcfba346a9844ccace356aeb186a826 | 是 | String | client_id |
client_secret | d80d5182071d43eeac45598ab89a99... | 是 | String | clientSecret |
refresh_token | OGQ5N2NHNWYTMDG3NC01M2ZLLTG1ZDCTZJCYZTA5MMYWYTC3 | 是 | String | refreshToken |
返回示例
{
"access_token": "ZWFMYMZJNGITOTLINY0ZMGMYLTKZM2ITMTFIYTI3ZDUXNDLI",
"expires_in": 7200,
"refresh_token": "ODQXMWQ2YTATYZQXYY01OTU4LTKZMTMTYWJIM2ZHZWVHZGFK",
"token_type": "Bearer"
}
# 使用token获取用户信息
应用通过 access_token 获取用户信息,同时会先校验token
- 接口URL: GET http://192.168.31.66:3500/account/api/v1/oauth/user
- 认证方式: Bearer auth
请求示例
import axios from "axios";
const options = {
method: 'GET',
url: 'http://192.168.31.66:3500/account/api/v1/oauth/user',
headers: {
lang: 'zh-CN',
Authorization: 'Bearer M2I1NWUWNWYTYMQ3NC0ZMZFMLWE1YMITYTRJODEXMJA0NZA2'
}
};
axios.request(options).then(function (response) {
console.log(response.data);
}).catch(function (error) {
console.error(error);
});
返回示例
{
"id": "67c2edc046b54371b54b4284af3050e4", //id
"userId": "67c2edc046b54371b54b4284af3050e4", //id
"name": "郭程豪", //名称
"username": "018470", //账户
"logo": "https://wework.qpic.cn/wwpic/630634_oZm07_oCQr6j5AU_1690886135/0", //logo
"email": "", //邮箱
"mobile": "185xxxx4250", //手机
"accessToken": "MTA0ZGRJNZATZWE4YS0ZZDGYLWEYNGQTMJGZMDFHMDVMZTFJ",
"accessTokenCreateAt": "2023-08-31T09:17:29.665587+08:00",
"accessTokenExpiresIn": 28800000000000,
"refreshToken": "MTQXMDHMNTGTYTEYNI01NJG0LTLLNJUTNJG3NMZHN2Y0MMNJ",
"refreshTokenCreateAt": "2023-08-31T09:17:29.665587+08:00",
"refreshTokenExpiresIn": 604800000000000
}
# 校验token是否有效
- 接口URL: GET http://192.168.31.66:3500/account/api/v1/oauth/token
- 认证方式: Bearer auth
请求示例
import axios from "axios";
const options = {
method: 'GET',
url: 'http://192.168.31.66:3500/account/api/v1/oauth/token',
headers: {
lang: 'zh-CN',
Authorization: 'Bearer M2I1NWUWNWYTYMQ3NC0ZMZFMLWE1YMITYTRJODEXMJA0NZA2'
}
};
axios.request(options).then(function (response) {
console.log(response.data);
}).catch(function (error) {
console.error(error);
});
返回成功示例
{
"message": "success" //描述
}
返回失败示例
{
"code": "ERR_INVALID_TOKEN", //返回码
"message": "Token 无效!" //错误描述
}