单点登录

一、单点登录介绍
单点登录的英文名叫做:Single Sign On(简称SSO)。以前的时候,大部分都是单应用系统,所有的功能都在同一个系统上。后来,为了合理利用资源和降低耦合性,于是把单系统拆分成多个子系统。比如我们常用的淘宝和天猫,很明显这是两个系统,但是你在使用的时候,登录了天猫,淘宝也会自动登录。简单来说,单点登录就是在多个系统中,用户只需登录一次,各个系统都可感知该用户已经登录,苍穹对于这种场景也有一套自己的实现。
二、第三方系统集成单点登录
1、需求
第三方应用登录时,使用金蝶云平台的云账号进行用户登录,登录成功后直接进入第三方应用。
2、思路与方案

第一步:用户登录第三方系统,第三方系统会调用金蝶云平台的登录页,需要使用authorize接口(详情见下方),用户需要登录金蝶云平台的账号。
第二步:金蝶云账号系统校验当前用户账号,成功后返回该用户的临时授权码code
第三步:第三方系统使用code换取用户的access_token,需要使用access_token接口(详情见下方)。
第四步:金蝶云账号系统校验code,成功后返回该用户的access_token。
第五步:如果第四步根据code,还无法获取用户手机号等信息,还要根据access_token才能获取手机号等用户信息。
3、实现过程
单点登录认证平台(这里使用云平台测试环境)注册一个新应用(后面用到应用id和应用密钥)。
云平台测试环境:https://p.cloudsz.kingdee.com/
云平台正式环境:https://cloud.kingdee.com/
3.2、订阅服务
3.2.1、订阅服务
在左侧”订阅新服务“中订阅以下两个服务,用以单点登录时获取授权信息。

然后两个服务都需要配置回调地址,这里先简单的聊一下回调地址是什么。比如你点击淘宝登录跳转到淘宝登录页面,经过淘宝后台处理登录成功后,应该要重定向回首页或者指定页,这个时候就需要回调地址。回调地址就是在这里用来指定跳转回网站的URL,但光有URL不行,我们还需要获取、绑定和关联用户信息到回调的页面,所以一般请求后都可以在重定向的地址中找到拼接的参数供后续的接口调用(如后文的code)。

3.2.2、金蝶云账号认证授权
后续的插件开发后api模拟都是建立在官方api接口的基础上,所以在阅读本部分前,强烈建议先阅读下官方api文档帮助理解。https://cloud.kingdee.com/help/document/detail?item=448&doc=2981

(1)接口路径
·https://api.cloudsz.kingdee.com/auth/oauth2/authorize(金蝶云账号认证授权服务接口)
(2)功能说明
· oauth2.0协议第一步,获取Authorization Code
(3)HTTP请求方式
· GET
(4)返回格式
· JSON
(5)请求参数
参数名称 | 必选 | 说明 |
client_id | true | 应用 ID |
response_type | true | 授权类型,此值固定为“code” |
redirect_uri | true | 回调地址,与注册回调地址的域名相同即可。回调地址在云之家认证授权服务下填写回调地址 |
display | false | 可用值有web,mobile,qronly,默认是web,display=mobile:移动端页面,display= qronly:显示二维码页面 |
force_login | false | 如果通行证已经登录,第三方应用授权登录时是否还需要登录:0:默认(PC端出现已登录用户头像,移动端出现登录框);1:需要(每次都出现登录框);2:不需要,直接授权回调应用(不会出现登录框和已登录用户状态),使用此参数,退出登录状态,需要使用logout接口,详见后续接口。 |
state | false | client端的状态值。用于第三方应用防止CSRF攻击,成功授权后回调时会原样带回,请将state设置为32位的随机数。请务必严格按照流程检查用户与state参数状态的绑定。 |
(6)请求示例:
"https://api.cloudsz.kingdee.com/auth/oauth2/authorize?&response_type=
code" +"&client_id=应用id"+"&redirect_uri="+UrlService.
getDomainContextUrl()+"?&state=" + URLEncoder.encode(ID.genStringId());
(7)返回参数
返回参数都从浏览器获得:
返回参数 | 字段类型 | 字段说明 |
code | string | 成功时通过回调地址返回参数code,[回调地址]?code=520DD95263C1CFEA0870FBB66E |
errcode | string | 如果有错误,通过回调地址返回错误代码 |
description | string | 如果有错误,通过回调地址返回错误描述 |
state | string | 如果调用有传递,则原样返回 |
3.2.2.2、校验授权码access_token
(1)接口路径
·https://api.kingdee.com/auth/oauth2/access_token
(2)接口描述
·第三方应用使用oauth2.0协议获取用户授权时,第二步获取用户访问access_token,同时包括用户基本信息。
(3)功能说明
·oauth2授权第二步,获取Access Token
(4)HTTP请求方式
·POST
(5)返回格式
·JSON
(6)认证方式:
·使用应用ID和应用Secret认证
(7)请求参数
参数名称 | 必选 | 说明 |
client_id | true | 应用ID |
client_secret | true | 应用安全码 |
grant_type | true | 目前固定传authorization_code |
redirect_uri | true | 回调地址 |
state | false | client端的状态值(authorize接口使用的state的值)。用于第三方应用防止CSRF攻击,成功授权后回调时会原样带回。请务必严格按照流程检查用户与state参数状态的绑定。 |
String accessTokenUrl = "https://api.cloudsz.kingdee.com/auth/oauth2/access_token?" +
"client_id=应用id"+
"&client_secret=应用安全码" +
"&grant_type=" + "authorization_code" +
"&code=" + 前面获取授权码返回的code值 +
"&redirect_uri=" +
URLEncoder.encode(UrlService.getDomainContextUrl()
+
"?" + queryString) +
"&state=" + URLEncoder.encode(ID.genStringId()) ;
JSONObject parse = (JSONObject) JSONObject.parse(HttpUtils.post(accessTokenUrl));
(9)返回参数
返回参数 | 字段类型 | 字段说明 |
errcode | string | 0:消息发送成功 其他值:消息发送不成功 |
description | string | 结果或错误描述 |
data | array | 数据结果集 |
state | string | 原样返回请求的该参数值 |
uid | integer | 用户ID |
nickname | string | 用户昵称 |
avatar | string | 用户头像 |
access_token | string | 用户的token |
expires_in | integer | access_token的生命周期,单位是秒数。 |
·通过oauth2.0授权的用户access_token的有效期只有7天,当access_token过期,或者使用access_token调用接口时返回状态401,则需要重新获取用户的授权。
3.2.2.3、金蝶云账号服务
(1)接口路径
· https://api.kingdee.com/account/user_info
(2)功能说明
· 通过用户access_token获取用户信息
(3)HTTP请求方式
· GET
(4)返回格式
· JSON
(5)请求参数
请求参数
参数名称 | 类型 | 必选 | 说明 |
access_token | string | true | 用户授权access_token |
返回参数
返回参数 | 字段类型 | 必选 | 字段说明 |
errcode | int | true | 0:消息发送成功 其他值:消息发送不成功 |
description | string | true | 结果或错误描述 |
uid | int | true | 用户的ID |
name | string | true | 用户真实姓名,可能为空值 |
nickname | string | true | 用户昵称 |
avatar | string | true | 用户头像地址 |
string | true | 用户自己填写的邮箱,可能为空值,不是登录邮箱 | |
phone | string | true | 用户自己填写的手机号码,可能为空值,不是登录手机号码 |
gender | int | true | 姓别。0:男 1:女 2:保密 |
3.3、苍穹单点登录代码示例
下面介绍如何根据金蝶云平台认证中心进行单点登录功能的开发。
3.3.1、注册sso插件
这里的第三方应用使用了本地的一个轻量级苍穹平台。
步骤 | 操作 |
第一步 | 新建sso插件继承于基类kd.bos.login.thirdauth.ThirdSSOAuthHandler |
第二步 | callTrdSSOLogin事件中重定向到统一认证中心(例如金蝶云平台) |
第三步 | getTrdSSOAuth事件中根据统一认证中心登录返回的code值获取accesstoken和用户信息 |
第四步 | 把sso插件注册到苍穹mc对应的数据中心中 |

3.3.2、获取授权码authorize
http://localhost:8081/ierp/登录时,重定向到认证平台。
/**
* @description TODO 需要根据访问目标系统构造登录后的url①,
* 需要根据来源的SSO系统构造目标登录url,并把①补充到redirect参数中
* <p>
* 用户需要登录的地址,打开苍穹将会重定向到此地址
* 该方法是用户没有登录的时候插件需要转移到正确的登录地址(苍穹登录页无法跳转此方法)
*/
@Override
public void callTrdSSOLogin(HttpServletRequest request, HttpServletResponse response, String backUrl) {
// 退出处理
if (request.getRequestURI().contains("logout.do")) {
logout(request);
SSOUtil.sendRedirect(response, "http://localhost:8081/ierp/");
return;
}
//判断是否成功登录 金蝶云通过code进行判断
String c = request.getParameter("code");
String s = request.getParameter("state");
if (StringUtils.isNotEmpty(c) && StringUtils.isNotEmpty(s)) {
return;
}
//sso插件重定向处理
if (request.getQueryString() != null && request.getQueryString().contains("flag=1")) {
return;
}
//正常登录访问苍穹,构造缓存数据
MultiMap<String> queryParameters = ((Request) request).getQueryParameters();
TargetInfo targetInfo = SSOUtil.buildTargetInfo(queryParameters);
targetInfo.getParam().put("queryParam", request.getQueryString());
//如果请求的url中有 logout表示是从退出的接口过来的。需要 到首页 或者登录页面页面 request.getRequestURI() ,同时最好清楚相关token缓存
//退出处理,默认到首页
//缓存数据,因为state参数可以保持同步返回,所以用来进行模拟线程安全处理,10分钟过期
String state = ID.genStringId();
targetInfo.setState(state);
DistributeSessionlessCache cache = CacheFactory.getCommonCacheFactory().getDistributeSessionlessCache("ssoLogin");
cache.put(state, JSONObject.toJSONString(targetInfo), 60);
//根据sso地址构造,登录地址 重定向到云平台
SSOUtil.sendRedirect(response, SSOUtil.buildLoginUrl(targetInfo, request));重定向到统一认证中心(云平台)进行金蝶云账号登录

3.3.3、获取用户access_token信息
获取根据认证平台返回的code值去获取用户token,再根据用户token获取详细的用户详细(用户手机号等)。
2、 /**
* 该方法实现第三发插件认证及认证结果的返回
*/
@Override
public UserAuthResult getTrdSSOAuth(HttpServletRequest request, HttpServletResponse response) {
UserAuthResult result = new UserAuthResult();
//判断是否成功登录 金蝶云通过code进行判断
String code = reques
单点登录
声明:除非特别标注,否则均为本站原创文章,转载时请以链接形式注明文章出处。如若本站内容侵犯了原著者的合法权益,可联系本站删除。



