统一门户功能
IDaaS的单点登录(Single Sign On,SSO)能力,可以为企业提供统一的门户。用户只需要认证登录一次,就可以访问所有集成了的应用系统。
这里主要调研了JWT和OAuth2.0两种协议模板方式对接。
JWT方式接入介绍
Json web token ( JWT ), 是一种用于双方之间传递安全信息的简洁的、URL安全的表述性声明规范。JWT作为一个开放的标准(RFC 7519),定义了一种简洁的,自包含的方法用于通信双方之间以 Json 对象的形式安全的传递信息,该 token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景
请求响应时序图:
实现原理:
SP 接收 IDaaS 平台向 callback url 发出的 id_token 参数(即 JWT 令牌),并使用我们提供的(或第三方提供的) JWT 解密库/方法对 JWT 进行解析,并验证身份。
1)用户通过浏览器登录 IDaaS ,并发起单点请求
2)IDaaS 生成 token 令牌发送到业务应用。
3)业务系统获取到 token 令牌,用我们提供的插件或方法解析 token 令牌,解析成功获取到用户信息并验证
验证通过:业务系统重定向到用户首页,
验证失败:业务系统拒绝登录并页面提示错误信息
第 1 步 创建 JWT 应用
1)登录 IDaaS 管理员平台
使用 IT 管理员账号登录云盾IDaaS管理控制台。具体操作请参考 IT管理员指南-登录。
2)添加 JWT 应用
在【应用】-【添加应用】中,找到应用名称为: JWT,点击右边【添加应用按钮】
3)填写信息并保存
参数说明:
-
图标:业务应用的 logo 图片。
-
应用 ID: 自动生成应用 ID,且唯一。
-
应用名称: 填写创建应用的名称。
-
应用类型: 代表该服务支持的设备类型,标记使用。
-
redirect_uri:业务系统中(或 PC 程序)的 JWT SSO 地址,在单点登录时 IDaaS 将向该地址用[GET]方式发送 ID_Token 信息,参数名为ID_Token,业务系统通过 ID_Token 与 Public Key 可获取业务系统中的用户信息,如果在业务系统(SP)发起登录,请求 SP 登录地址时如果携带 Service 参数 IDaaS 会检验合法性,成功后会将浏览器重定向到该地址,并携带ID_Token身份令牌。
-
Target_link_uri: 业务系统中在 JWT SSO 成功后重定向的 URI,一般用于跳转到二级菜单等,若设置了该 URI,在 JWT SSO 时会以参数 Target_link_uri 优先传递该值,若未设置该值,此时若SSO中有请求参数。
7.是否包含用户角色:用于第三方权限系统对接,开启后会将账户的角色信息包含在 ID_Token 中。
8.SSO Binding:单点登陆请求方式,REDIRECT 为 GET 类型,也可选择 POST。
9.ID_Token有效期:单位秒。
10.是否显示应用:授权给用户后,是否在用户首页显示。默认开启,若关闭,用户登录将看不到该应用。
11.账户关联方式:
a.账户关联(系统按主子账户对应关系进行手动关联,用户添加后需要管理员审批)
b.账户映射(系统自动将主账户名称或指定的字段映射为应用的子账户)
4)导出公钥
完成上面应用创建,我们在【应用列表】中,就可以找到新创建的应用。点击【详情】按钮,点击【查看详情】。
找到 JWT PublicKey
复制粘贴到文本txt,或者使用下方导出,都可以将 JWT PublicKey 导出。将其交给第三方也系统,用作 ID_Token 解析。
第 2 步 SDK 下载
在这里,第三方业务系统就要开始研发的准备工作了。我们提供 4 种语言的 SDK 集成方式。
JAVA/PHP/.NET/Python ,当然,如果您的业务系统是其他语言也可以进行对接,需要您自行编写解析 ID_Token 的代码。可以参考:
下载方式:
1)登录到 IDaaS 管理平台。登录操作,请参考 开发者访问方式
2)切换至【开发者】
3)点击【单点登录(SSO)】- 点击【单点登录(SSO)开发者文档】
4)在右侧导航栏最下方找到 【其他】-【相关下载】,按需下载即可
第 3 步 业务系统研发【重要】
研发核心思想:
1)能够接收到令牌
2)能够成功解析令牌,拿到 用户信息
3)匹配用户信息是否与当前自己的账号一致
4)跳转至用户首页
1)JAVA 插件式集成
配置环境
JDK 1.6 以上
接收令牌
// id_token 是 IDaaS 请求时带来的,在 body 里获取,PublicKey是在 IDaaS 里注册应用时生成的,注册完可见,此示例代码是获取用户信息。
// JWT SSO
@RequestMapping(value = “/JWT/sso/login”)
public String SSO Url(@RequestParam String id_token, String redirect_url, Model model, HttpServletRequest request){
//1.接收方法为GET方式,参数名为 id_token
//2.<解析令牌>为解析 id_token 并验证代码
}
解析令牌
PublicKey: 解析令牌的过程中,我们会使用到应用的 PublicKey。请在 JWT 应用 -> 详细 中将PublicKey字段对应的内容拷贝并存储起来。
//1.使用公钥,解析 id_token
// 使用PublicKey解密上一步获取的 id_token 令牌
DingdangUserRetriever retriever = new DingdangUserRetriever( id_token, PublicKey);
DingdangUserRetriever.User user = null;
try {
//2.获取用户信息
user = retriever.retrieve();} catch (Exception e) {
LOG.warn(“Retrieve SSO user failed”, e);
return “error”;
}
//3.判断用户名是否在自己系统存在isExistedUsername()方法为业务系统自行判断数据库中是否存在
if (isExistedUsername(user.getUsername())) {
//4.如果存在,登录成功,返回登录成功后的页面
User SPUser = userService.updateLoginTimes(user.getUsername());
request.get session ().setAttribute(Http session SecurityContextRepository. SPRING_SECURITY_CONTEXT_KEY, saveSecurity( SP User));
//5.如果注册时添加redirect_url,那么返回此自定义url页面
if (StringUtils.isNotEmpty(redirect_url)) {
return “redirect:” + redirect_url;
}
//6.否则返回系统默认操作页面
return “redirect:../../index”;
} else {
//7.如果不存在,返回登录失败页面,提示用户不存在
model.addAttribute(“error”, “username { “ + user.getUsername() + “ } not exist”);
return “error”;
}
OAuth2.0方式接入介绍
OAuth2是一个开放的资源授权协议,应用可以通过 OAuth 获取到令牌 access_token,并携带令牌来服务端请求用户资源。应用可以使用 OAuth 应用模板来实现统一身份管理。
请求时序图:
操作步骤
- 以IT管理员账号登录云盾IDaaS管理平台。具体操作请参考 IT管理员指南-登录。
- 点击左侧导航栏应用 > 添加应用。
- 选择OAuth2应用模板点击添加应用。
-
- Redirect URI : 填写需要使用OAuth2单点登录应用的URL,如:lab.galaxy.ant-galaxy.com(可更改)
- GrantType : 选择authorization_code
-
查看 OAuth2 应用详情, 获得 Client Id、Client Secret、Authorize URL.
说明:如果您希望应用系统每次登录时,都需要强制到IDaaS进行认证,在调用的 Authorize URL 后加上 prompt=login 参数即可。
-
使用浏览器打开 Authorize URL, 使用授权的账户进行登录,登录成功后跳转到回调地址,从浏览器地址栏提取 code 参数的值.
-
使用 POSTMAN 发送 POST 请求到 https://{IDaaS_server}/oauth/token?grant_type=authorization_code&code={code}&client_id={client_id}&client_secret={client_secret}&redirect_uri={redirect_uri}
-
- {IDaaS_server}需要替换为真实IDaaS服务器地址
说明 IDaaS服务器地址获取方式:访问云盾IDaaS管理控制台,使用用户访问的Portal的地址
- {code}需要替换为第 6 步中提取到的 code 参数的值。
注意 Code 的值只能用一次 - {client_id}、{client_secret}需要替换为第 5 步中获得的值
- {redirect_uri} 需要替换为第 2 步添加 OAuth2 应用时输入的跳转值
- {IDaaS_server}需要替换为真实IDaaS服务器地址
- IDaaS服务器将会响应 access_token, 使用该值可访问 IDaaS服务器资源
- 使用 POSTMAN 发送 GET 请求到 https://{IDaaS_server} /api/bff/v1.2/oauth2/userinfo?access_token={access_token}
说明 其中v1.2是版本,根据实际版本填写。如果js中没有写版本号,那么此处写v1;如果写了版本号,就写对应的版本号
具体接口
- Request URI: /oauth/token
-
- 接口说明:获得 access_token
- 请求参数
| 参数 | 类型 | 是否必选 | 示例值 | 描述 |
|---|---|---|---|---|
| code | string | 是 | vuQ3n6 | 用户登录成功后回调传递的code值 |
| client_id | string | 是 | oauth2 client_id | OAuth2 client_id |
| client_secret | string | 是 | oauth2 client_secret | OAuth2 client_secret |
| redirect_uri | string | 是 | example.com | 重定向 url |
-
- 返回参数
| 参数 | 类型 | 示例值 | 描述 |
|---|---|---|---|
| access_token | string | 333ab704-abc0-48b3-8af0-496eedd15383 | Access Token |
| token_type | string | bearer | Token 类型 |
| expires_in | string | 7199 | Access Token 过期时间 |
| scope | string | read | 申请的权限范围 |
-
- 错误码说明
| HttpCode | 错误码 | 错误信息 | 描述 |
|---|---|---|---|
| 400 | invalid_grant | Invalid authorization code: "code". | 无效的授权码 |
| 400 | invalid_grant | Redirect URI mismatch. | 重定向 URI 不匹配 |
| 401 | Unauthorized | Unauthorized | 未授权的访问 |
| 403 | Forbidden | Forbidden | 无权限访问 |
| 404 | ResourceNotFound | ResourceNotFound | 访问的资源不存在 |
| 415 | UnsupportedMediaType | UnsupportedMediaType | 不支持的媒体类型 |
| 500 | InternalError | The request processing has failed due to some unknown error, exception or failure. | 发生未知错误 |
- Request URI: /api/bff/v1.2/oauth2/userinfo
-
- 接口说:获取用户详细信息
- 请求参数
| 参数 | 类型 | 是否必选 | 示例值 | 描述 |
|---|---|---|---|---|
| access_token | string | 是 | 333ab704-abc0-48b3-8af0-496eedd15383 | Access Token |
-
- 返回参数响应示例
{
"success": true,
"code": "200",
"message": null,
"requestId": "59C5766B-C7F9-4DF6-B5E4-0F2A89942749",
"data": {
"sub": "4982789226325725762",
"ou_id": "5920417439492153461",
"nickname": "admin",
"phone_number": null,
"ou_name": "PG China",
"email": "sz@xxxx.com",
"username": "admin_wli"
}
}
-
- 参数说明
| 参数 | 类型 | 示例值 | 描述 |
|---|---|---|---|
| sub | string | 4982789226325725762 | 账户的外部ID |
| username | string | admin_wli | 用户名 |
| nickname | string | admin | 显示名称 |
| string | sz@xxxx.com | 邮箱 | |
| phone_number | string | null | 手机号 |
| ou_name | string | PG China | 账户所属组织机构名称 |
| ou_id | string | 5920417439492153461 | 账户所属组织机构外部ID |
-
- 错误码说明
| HttpCode | 错误码 | 错误信息 | 描述 |
|---|---|---|---|
| 401 | Unauthorized | Unauthorized | 未授权的访问 |
| 403 | Forbidden | Forbidden | 无权限访问 |
| 404 | ResourceNotFound | ResourceNotFound | 访问的资源不存在 |
| 415 | UnsupportedMediaType | UnsupportedMediaType | 不支持的媒体类型 |
| 500 | InternalError | The request processing has failed due to some unknown error, exception or failure. | 发生未知错误 |
其它
1. 是否支持OAuth2退出
在登录接口增加proxmy参数, 当prompt=login则强制跳转登录页 , 也就是在下图 Authorize URL后面增加“&prompt=login ”
开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 28 天,点击查看活动详情