Edge测试插件地址
插件安装: https://microsoftedge.microsoft.com/addons/detail/crossrequest/bephiepmhphdlafkfonngafenjhfehlb
当前应用的域,在应用部署后, 应用如果使用的是FMES内容应用, 其IAM系统会分享一下接口给部署的应用
| 接口 | 备注 |
|---|---|
| /api/iam/v1/a/odic/login | 应用登录接口 |
| /api/iam/v1/a/odic/callback | IAM系统回调接口 |
| /api/iam/v1/a/odic/logout | 应用登出接口 |
| /api/iam/v1/odic/authc | 应用鉴权接口 |
对于第三方应用, 可以使用账户中心域名:
测试环境:http://account.dev.k8s.local
正式环境:http://account.con.plscn.com
| 名称 | 类型 | 默认值 | 是否必须 | 说明 | 备注 |
|---|---|---|---|---|---|
| success | boolean | 必须 | 请求状态 | ||
| data | object | 非必须 | 请求内容 | ||
| errorCode | string | 非必须 | 异常编码 | ||
| errorMessage | string | 非必须 | 异常内容 | ||
| showType | integer | 非必须 | 前端动作 | ||
| traceId | string | 必须 | 追踪ID |
{
"success": false,
"data": "string",
"errorCode": "S_SERVE_FORBIDDEN",
"errorMessage": "用户未得到授权,访问是被禁止的",
"showType": 1,
"traceId": "e59e6f078389d36c2bb06d29297b5b86"
}
前端动作类型, 页面的内容应该有前端拦截器统一处理
| 名称 | 类型 | 值 | 动作 | 备注 |
|---|---|---|---|---|
| ShowNone | 0 | 静音 | ||
| ShowWarn | 1 | 消息警告 | ||
| ShowError | 2 | 消息错误 | ||
| ShowNotify | 4 | 通知 | ||
| ShowPage | 9 | 页面跳转 |
Path: /authx
Method: GET
接口描述:
该内容为网关层调用,与具体业务应用无关,请求路由到业务接口前已经通过平台IAM网关处理,网关会在转发的请求上增加下面的Serve, Sessionid, Authorize, Signature内容。子应用只需要处理请求头上的内容完成授权即可。
框架中的Kratos.getUser方法可以直接得到用户的登陆信息,无需单独处理请求头上的内容
请求头
| 参数 | 类型 | 描述 | 说明 | |
|---|---|---|---|---|
| X-Request-Sky-Serve | Header | 验证服务器 | ||
| X-Request-Sky-Sessionid | Header | 账户SessionId | ||
| X-Request-Sky-Authorize | Header | 用户信息载体 | ||
| X-Request-Sky-Signature | Header | 用户信息签名 | 用户验证载体信息的正确性 |
X-Request-Sky-Authorize: 内容为Base64加密的JSON内容, 通过Base64解密即可得到用户详细信息。以下是用户载体中的内容:推荐使用fasterjson解析内容, 如果使用非fasterjson解析, 需要替换注解内容。
String authorize = request.getHeader("X-Request-Sky-Authorize"):
byte[] bts = Base64.getDecoder().decode(authorize);
UserCtx ctx2 = JSON.parseObject(bts, UserCtx.class);
用户上下文内容:
/**
* 用户上下文
*
* @author <a href="mailto:suisrc@outlook.com">Y13</a>
*/
@Data
public class UserCtx implements UserI {
// 上下文ID
@JSONField(serialize = false)
private String contextId;
@JSONField(serialize = false)
private String requestId;
@JSONField(serialize = false)
private String clientIp;
// UserClaims
@JSONField(name = "jti")
private String id;
@JSONField(name = "aud")
private String audience;
@JSONField(name = "exp")
private String expiredAt;
@JSONField(name = "iat")
private String issuedAt;
@JSONField(name = "iss")
private String issuer;
@JSONField(name = "nbf")
private String notBefore;
@JSONField(name = "sub")
private String subject;
@JSONField(name = "nam")
private String name;
@JSONField(name = "rol")
private String role; // 请看tenant_role_code
@JSONField(name = "flw")
private String flow;
@JSONField(name = "akd")
private String accountKind;
@JSONField(name = "atc")
private String userTmpCode;
@JSONField(name = "nonce")
private String nonce;
// IdInfo
@JSONField(name = "ids")
private String ids;
@JSONField(serialize = false)
private Integer accountId;
@JSONField(serialize = false)
private Integer userId;
@JSONField(serialize = false)
private Integer appId;
@JSONField(serialize = false)
private Integer tenantId;
@JSONField(serialize = false)
private Integer tenantUserId;
@JSONField(serialize = false)
private Integer tenantRoleId;
@JSONField(serialize = false)
private Integer tenantDirId;
@JSONField(serialize = false)
private Integer tenantAppId;
@JSONField(name = "id2")
private Integer[] id2;
// UserInfo
@JSONField(name = "uco")
private String userCode;
@JSONField(name = "una")
private String userName;
@JSONField(name = "three")
private String three;
@JSONField(name = "agent")
private String agent;
@JSONField(name = "scope")
private String scope;
// TenantInfo
@JSONField(name = "tkd")
private String tenantKind;
@JSONField(name = "tco")
private String tenantCode;
@JSONField(name = "tna")
private String tenantName;
@JSONField(name = "tuc")
private String tenantUserCode;
@JSONField(name = "tcc")
private String tenantUserCcde;
@JSONField(name = "tun")
private String tenantUserName;
@JSONField(name = "app")
private String tenantAppCode;
@JSONField(name = "apn")
private String tenantAppName;
@JSONField(name = "trc")
private String tenantRoleCode;
@JSONField(name = "trn")
private String tenantRoleName;
@JSONField(name = "tpg")
private String tenantPrivilege;
@JSONField(name = "tup")
private String tenantUserPhone;
/**
* 异常
*/
private ErrorCodeException error;
// ======================================================
// ======================================================
// ======================================================
public String getAccountCode() {
return subject;
}
public String getAccountName() {
return name;
}
@Override
public boolean verify() {
if (error != null) {
throw error;
} else if (accountId == null) {
// throw Errors.Err401Unauthorized // 业务代理中不能使用401异常
// 否则会导致平台在IAM和业务系统间无限跳转异常
throw Errors.Err403Unauthorized;
}
return true;
}
}
X-Request-Sky-Signature: 用户载体签名, 防止用户内容被篡改。publicKey为平台IAM系统颁发给子应用的验签公钥。Sign通过request.getHeader("X-Request-Sky-Authorize")方式取得。
/**
* @param content:验证参数的内容
* @param sign:签名
* @param publicKey:公钥
* @return
*/
public boolean verifySign(String authorize, String sign, String publicKey) {
try {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
byte[] encodedKey = Base64.getDecoder().decode(publicKey);
PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initVerify(pubKey);
signature.update(content.getBytes());
return signature.verify(Base64.getUrlDecoder().decode(sign));
} catch (Exception e) {
// throw new RuntimeException(e)
return false;
}
}
平台业务应用无需访问平台IAM鉴权系统。请求通过平台网关后, 会将请求优先转发到IAM系统完成权限认证。如果认证失败,IAM系统直接通知平台网关将结果返回给客户端。如果鉴权成功,鉴权的结果, 包含用户信息载体和用户信息签名附件到请求上,继续向上游业务系统路由。
业务系统,需要内部调用其他业务应用资源,使用以上4个header内容附加到请求上。即到达其他应用资源权限校验。
Headers
| 参数名称 | 参数值 | 是否必须 | 示例 | 备注 |
|---|---|---|---|---|
| Content-Type | application/json | 是 | application/json | 编码方式 |
| Authorization | 是 | Bearer XXXX | 访问令牌 | |
| X-Request-Origin-Host | 是 | 127.0.0.1 | 访问的客户端IP | |
| X-Request-Origin-Path | 是 | /api/v1 | 访问的路径 | |
| X-Request-Origin-Method | 是 | GET | 访问的方法,ET, POST, DELETE, PUT |
| 名称 | 类型 | 是否必须 | 默认值 | 备注 | 其他信息 |
|---|---|---|---|---|---|
| success | boolean | 必须 | 请求状态 | ||
| data | string | 非必须 | 请求结果 | ||
| errorCode | string | 非必须 | 异常编码 | ||
| errorMessage | string | 非必须 | 异常内容 | ||
| showType | number | 非必须 | 前端动作 | ||
| traceId | string | 必须 | 追踪ID |
Path: /authz
Method: GET
接口描述:
该内容为网关层调用,与具体业务应用无关,请求路由到业务接口前已经通过平台IAM网关处理,网关会在转发的请求上增加下面的Serve, Sessionid, Authorize, Signature内容。子应用只需要处理请求头上的内容完成授权即可。
框架中的Kratos.getUser方法可以直接得到用户的登陆信息,无需单独处理请求头上的内容
请求头
| 参数 | 类型 | 描述 | 说明 | |
|---|---|---|---|---|
| X-Request-Sky-Serve | Header | 验证服务器 | ||
| X-Request-Sky-Sessionid | Header | 账户SessionId | ||
| X-Request-Sky-Authorize | Header | 用户信息载体 | ||
| X-Request-Sky-Signature | Header | 用户信息签名 | 用户验证载体信息的正确性 |
X-Request-Sky-Authorize: 内容为Base64加密的JSON内容, 通过Base64解密即可得到用户详细信息。以下是用户载体中的内容:推荐使用fasterjson解析内容, 如果使用非fasterjson解析, 需要替换注解内容。
String authorize = request.getHeader("X-Request-Sky-Authorize"):
byte[] bts = Base64.getDecoder().decode(authorize);
UserCtx ctx2 = JSON.parseObject(bts, UserCtx.class);
用户上下文内容:
/**
* 用户上下文
*
* @author <a href="mailto:suisrc@outlook.com">Y13</a>
*/
@Data
public class UserCtx implements UserI {
// 上下文ID
@JSONField(serialize = false)
private String contextId;
@JSONField(serialize = false)
private String requestId;
@JSONField(serialize = false)
private String clientIp;
// UserClaims
@JSONField(name = "jti")
private String id;
@JSONField(name = "aud")
private String audience;
@JSONField(name = "exp")
private String expiredAt;
@JSONField(name = "iat")
private String issuedAt;
@JSONField(name = "iss")
private String issuer;
@JSONField(name = "nbf")
private String notBefore;
@JSONField(name = "sub")
private String subject;
@JSONField(name = "nam")
private String name;
@JSONField(name = "rol")
private String role; // 请看tenant_role_code
@JSONField(name = "flw")
private String flow;
@JSONField(name = "akd")
private String accountKind;
@JSONField(name = "atc")
private String userTmpCode;
@JSONField(name = "nonce")
private String nonce;
// IdInfo
@JSONField(name = "ids")
private String ids;
@JSONField(serialize = false)
private Integer accountId;
@JSONField(serialize = false)
private Integer userId;
@JSONField(serialize = false)
private Integer appId;
@JSONField(serialize = false)
private Integer tenantId;
@JSONField(serialize = false)
private Integer tenantUserId;
@JSONField(serialize = false)
private Integer tenantRoleId;
@JSONField(serialize = false)
private Integer tenantDirId;
@JSONField(serialize = false)
private Integer tenantAppId;
@JSONField(name = "id2")
private Integer[] id2;
// UserInfo
@JSONField(name = "uco")
private String userCode;
@JSONField(name = "una")
private String userName;
@JSONField(name = "three")
private String three;
@JSONField(name = "agent")
private String agent;
@JSONField(name = "scope")
private String scope;
// TenantInfo
@JSONField(name = "tkd")
private String tenantKind;
@JSONField(name = "tco")
private String tenantCode;
@JSONField(name = "tna")
private String tenantName;
@JSONField(name = "tuc")
private String tenantUserCode;
@JSONField(name = "tcc")
private String tenantUserCcde;
@JSONField(name = "tun")
private String tenantUserName;
@JSONField(name = "app")
private String tenantAppCode;
@JSONField(name = "apn")
private String tenantAppName;
@JSONField(name = "trc")
private String tenantRoleCode;
@JSONField(name = "trn")
private String tenantRoleName;
@JSONField(name = "tpg")
private String tenantPrivilege;
@JSONField(name = "tup")
private String tenantUserPhone;
/**
* 异常
*/
private ErrorCodeException error;
// ======================================================
// ======================================================
// ======================================================
public String getAccountCode() {
return subject;
}
public String getAccountName() {
return name;
}
@Override
public boolean verify() {
if (error != null) {
throw error;
} else if (accountId == null) {
// throw Errors.Err401Unauthorized // 业务代理中不能使用401异常
// 否则会导致平台在IAM和业务系统间无限跳转异常
throw Errors.Err403Unauthorized;
}
return true;
}
}
X-Request-Sky-Signature: 用户载体签名, 防止用户内容被篡改。publicKey为平台IAM系统颁发给子应用的验签公钥。Sign通过request.getHeader("X-Request-Sky-Authorize")方式取得。
/**
* @param content:验证参数的内容
* @param sign:签名
* @param publicKey:公钥
* @return
*/
public boolean verifySign(String authorize, String sign, String publicKey) {
try {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
byte[] encodedKey = Base64.getDecoder().decode(publicKey);
PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initVerify(pubKey);
signature.update(content.getBytes());
return signature.verify(Base64.getUrlDecoder().decode(sign));
} catch (Exception e) {
// throw new RuntimeException(e)
return false;
}
}
平台业务应用无需访问平台IAM鉴权系统。请求通过平台网关后, 会将请求优先转发到IAM系统完成权限认证。如果认证失败,IAM系统直接通知平台网关将结果返回给客户端。如果鉴权成功,鉴权的结果, 包含用户信息载体和用户信息签名附件到请求上,继续向上游业务系统路由。
业务系统,需要内部调用其他业务应用资源,使用以上4个header内容附加到请求上。即到达其他应用资源权限校验。
Headers
| 参数名称 | 参数值 | 是否必须 | 示例 | 备注 |
|---|---|---|---|---|
| Content-Type | application/json | 是 | application/json | 编码方式 |
| Authorization | 是 | Bearer XXXX | 访问令牌 | |
| X-Request-Origin-Host | 是 | 127.0.0.1 | 访问的客户端IP | |
| X-Request-Origin-Path | 是 | /api/v1 | 访问的路径 | |
| X-Request-Origin-Method | 是 | GET | 访问的方法,ET, POST, DELETE, PUT |
| 名称 | 类型 | 是否必须 | 默认值 | 备注 | 其他信息 |
|---|---|---|---|---|---|
| success | boolean | 必须 | 请求状态 | ||
| data | string | 非必须 | 请求结果 | ||
| errorCode | string | 非必须 | 异常编码 | ||
| errorMessage | string | 非必须 | 异常内容 | ||
| showType | number | 非必须 | 前端动作 | ||
| traceId | string | 必须 | 追踪ID |
Path: /authc
Method: GET
接口描述:
用户用户访问鉴权
{
"success": false,
"errorCode": "S_UNAUTHORIZED_INVALID-TOKEN",
"errorMessage": "用户没有权限(请求令牌无效)",
"showType": 1,
"traceId": "ccff7913a6a4e746f4c19a559d746fa0"
}
{
"success": false,
"errorCode": "S_SERVE_FORBIDDEN",
"errorMessage": "用户未得到授权,访问是被禁止的",
"showType": 1,
"traceId": "e59e6f078389d36c2bb06d29297b5b86"
}
{
"success": true,
"data": "ok",
"traceId": "ced0b4187066b2a7d52a2f34ce8b5c65"
}
Headers
| 参数名称 | 参数值 | 是否必须 | 示例 | 备注 |
|---|---|---|---|---|
| Content-Type | application/json | 是 | application/json | |
| Authorization | Bearer XXXX | 是 | Bearer XXXX | 访问令牌, cookie中如果存在kat, 该参数可以为空 |
Query
| 参数名称 | 是否必须 | 示例 | 备注 |
|---|---|---|---|
| method | 是 | GET | 请求方法,GET , POST, PUT, DELETE |
| path | 是 | /api/v1 | 清理路径 |
| 名称 | 类型 | 是否必须 | 默认值 | 备注 | 其他信息 |
|---|---|---|---|---|---|
| success | boolean | 必须 | 是否成功 | ||
| data | string | 非必须 | 结果,发生异常,该值不存在 | ||
| errorCode | string | 非必须 | 异常编码,成功后,该值不存在 | ||
| errorMessage | string | 非必须 | 异常内容 | ||
| showType | number | 非必须 | 前端反应 | ||
| traceId | string | 必须 | 追踪编码,用于追踪集 |
Path: /authc
Method: POST
接口描述:
访问权限鉴定(单)
用户用户访问鉴权
{
"success": false,
"errorCode": "S_UNAUTHORIZED_INVALID-TOKEN",
"errorMessage": "用户没有权限(请求令牌无效)",
"showType": 1,
"traceId": "ccff7913a6a4e746f4c19a559d746fa0"
}
{
"success": true,
"data": {
"KEY1": false,
"KEY2": true
},
"traceId": "993f452303a796ab44447ac5f84ceb87"
}
Headers
| 参数名称 | 参数值 | 是否必须 | 示例 | 备注 |
|---|---|---|---|---|
| Content-Type | application/json | 是 | application/json | |
| Authorization | Bearer XXXX | 是 | Bearer XXXX | 访问令牌, cookie中如果存在kat, 该参数可以为空 |
Body
| 名称 | 类型 | 是否必须 | 默认值 | 备注 | 其他信息 |
|---|---|---|---|---|---|
| KEY1 | object | 必须 | 鉴权资源编码 | ||
| ├─ method | string | 必须 | 鉴权内容的方法 | ||
| ├─ path | string | 必须 | 鉴权内容的路径 | ||
| KEY2 | object | 必须 | 鉴权资源编码 | ||
| ├─ method | string | 必须 | 鉴权资源的方法 | ||
| ├─ path | string | 必须 | 鉴权资源的路径 |
| 名称 | 类型 | 是否必须 | 默认值 | 备注 | 其他信息 |
|---|---|---|---|---|---|
| success | boolean | 必须 | 请求状态 | ||
| data | object | 必须 | 结果 | ||
| ├─ KEY1 | boolean | 必须 | 鉴权资源的结果 | ||
| ├─ KEY2 | boolean | 必须 | 鉴权资源的结果 | ||
| errorCode | string | 非必须 | 异常编码 | ||
| errorMessage | string | 非必须 | 异常内容 | ||
| showType | number | 非必须 | 前端动作 | ||
| traceId | string | 必须 | 追踪ID |
Path: /api/iam/v1/a/odic/authc
Method: GET
接口描述:
用户用户访问鉴权
{
"success": false,
"errorCode": "S_UNAUTHORIZED_INVALID-TOKEN",
"errorMessage": "用户没有权限(请求令牌无效)",
"showType": 1,
"traceId": "ccff7913a6a4e746f4c19a559d746fa0"
}
{
"success": false,
"errorCode": "S_SERVE_FORBIDDEN",
"errorMessage": "用户未得到授权,访问是被禁止的",
"showType": 1,
"traceId": "e59e6f078389d36c2bb06d29297b5b86"
}
{
"success": true,
"data": "ok",
"traceId": "ced0b4187066b2a7d52a2f34ce8b5c65"
}
Headers
| 参数名称 | 参数值 | 是否必须 | 示例 | 备注 |
|---|---|---|---|---|
| Content-Type | application/json | 是 | application/json | |
| Authorization | Bearer XXXX | 是 | Bearer XXXX | 访问令牌, cookie中如果存在kat, 该参数可以为空 |
Query
| 参数名称 | 是否必须 | 示例 | 备注 |
|---|---|---|---|
| method | 是 | GET | 请求方法,GET , POST, PUT, DELETE |
| path | 是 | /api/v1 | 清理路径 |
| 名称 | 类型 | 是否必须 | 默认值 | 备注 | 其他信息 |
|---|---|---|---|---|---|
| success | boolean | 必须 | 是否成功 | ||
| data | string | 非必须 | 结果,发生异常,该值不存在 | ||
| errorCode | string | 非必须 | 异常编码,成功后,该值不存在 | ||
| errorMessage | string | 非必须 | 异常内容 | ||
| showType | number | 非必须 | 前端反应 | ||
| traceId | string | 必须 | 追踪编码,用于追踪集 |
Path: /api/iam/v1/a/odic/authc
Method: POST
接口描述:
访问权限鉴定(单)
用户用户访问鉴权
{
"success": false,
"errorCode": "S_UNAUTHORIZED_INVALID-TOKEN",
"errorMessage": "用户没有权限(请求令牌无效)",
"showType": 1,
"traceId": "ccff7913a6a4e746f4c19a559d746fa0"
}
{
"success": true,
"data": {
"KEY1": false,
"KEY2": true
},
"traceId": "993f452303a796ab44447ac5f84ceb87"
}
Headers
| 参数名称 | 参数值 | 是否必须 | 示例 | 备注 |
|---|---|---|---|---|
| Content-Type | application/json | 是 | application/json | |
| Authorization | Bearer XXXX | 是 | Bearer XXXX | 访问令牌, cookie中如果存在kat, 该参数可以为空 |
Body
| 名称 | 类型 | 是否必须 | 默认值 | 备注 | 其他信息 |
|---|---|---|---|---|---|
| KEY1 | object | 必须 | 鉴权资源编码 | ||
| ├─ method | string | 必须 | 鉴权内容的方法 | ||
| ├─ path | string | 必须 | 鉴权内容的路径 | ||
| KEY2 | object | 必须 | 鉴权资源编码 | ||
| ├─ method | string | 必须 | 鉴权资源的方法 | ||
| ├─ path | string | 必须 | 鉴权资源的路径 |
| 名称 | 类型 | 是否必须 | 默认值 | 备注 | 其他信息 |
|---|---|---|---|---|---|
| success | boolean | 必须 | 请求状态 | ||
| data | object | 必须 | 结果 | ||
| ├─ KEY1 | boolean | 必须 | 鉴权资源的结果 | ||
| ├─ KEY2 | boolean | 必须 | 鉴权资源的结果 | ||
| errorCode | string | 非必须 | 异常编码 | ||
| errorMessage | string | 非必须 | 异常内容 | ||
| showType | number | 非必须 | 前端动作 | ||
| traceId | string | 必须 | 追踪ID |