单点登录
一、单点登录介绍
单点登录的英文名叫做: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 = request.getParameter("code");
String state = request.getParameter("state");
if (StringUtils.isEmpty(code) || StringUtils.isEmpty(state)) {
result.setErrDesc("单点登录失败");
return result;
}
//获取构造缓存
DistributeSessionlessCache cache = CacheFactory.getCommonCacheFactory().getDistributeSessionlessCache("ssoLogin");
String targetInfo = cache.get(state);
TargetInfo targetEntry;
if (StringUtils.isEmpty(targetInfo)) {
targetEntry = SSOUtil.buildTargetInfo(((Request) request).getQueryParameters());
} else {
targetEntry = JSONObject.parseObject(targetInfo, TargetInfo.class);
}
targetEntry.getParam().put("code", code);
//重定向到指定页面:
Object queryParamObj = targetEntry.getParam().get("queryParam");
if (!request.getQueryString().contains("flag=1")) {
try {
String url = UrlService.getDomainContextUrl() + "/?code=" + code + "&state=" + URLEncoder.encode(state, "utf-8") + "&" + queryParamObj + "&flag=1";
logger.info("2.添加指定页面&flag参数,重定向到苍穹指定页面,url={}", url);
response.sendRedirect(url);
result.setSucess(false);
cache.put(state, targetEntry.toString(), 60);
return result;
} catch (IOException e) {
e.printStackTrace();
}
}
//1.云平台获取用户认证信息:userinfo,2.封装登录认证结果 :authResult
JSONObject userInfo = KDCSSOUtil.getKDCUserAuth(targetEntry, result);
targetEntry.getParam().put("userInfo", userInfo.toJSONString());
cache.put(state, targetEntry.toString());
//3.缓存开发者信息userinfo,登录成功后@processSucceedLogin创建用户使用
request.setAttribute("userInfo", userInfo);
//设置登录成功:数据中心
String accountId = request.getParameter("accountId");
if (StringUtils.isNotEmpty(accountId) && accountId.equalsIgnoreCase("你的数据中心")) {
result.setAccountId(accountId);
}
return result;
}
3.3.4、参考代码
三、系统与系统间集成单点登录
1、需求
在多个系统中,用户只需登录一次,各个系统都可感知该用户已经登录,即A系统登录的情况下,B、C…系统不需要重新登录。
2、思路与方案
第一步:用户已经登录A系统,需要从A系统跳转至B系统。A系统需要换取用户登录B系统的专用code,需要使用auth_code接口(详情见下方)
第二步:金蝶云账号系统校验当前用户的access_token,成功后返回该用户登录B系统的专用code
第三步:A系统携带B系统的专用code将用户重定向至B系统
第四步:B系统使用code换取用户的access_token,需要使用validation接口(详情见下方)
第五步:金蝶云账号系统校验code,成功后返回该用户的access_token
3、实现过程
上面用代码实现了某A系统的单点登录过程,下面用postman模拟在A系统登录的情况下,跳转到B系统时,获取用户授权信息的过程。
3.1、获取授权码
(1)接口路径
·https://api.cloudsz.kingdee.com/auth/user/auth_code
(2)功能说明
· 获取用户access_token后,如果要一键登录金蝶云及相关应用、或其它第三方应用,需要先获取一次授权的auth_code。通过auth_code可以不用输入用户名密码就可以登录金蝶云WEB服务。把auth_code发给另一个第三方应用,可以通过auth_code获取用户信息。
· GET/POST
· JSON
·用户的access_token认证。
参数名称 | 必选 | 类型 | 说明 |
access_token | true | string | 用户的token |
target_id | false | string | 指定要访问的其它应用的client_id。 当其它应用需要限制访问的来源时, 可以判断当前的auth_code目标是否是自己。 |
(7)请求示例
https://api.cloudsz.kingdee.com/auth/user/auth_code?access_token=0b8e41fc2187a9110c6352ae812c54d9
返回参数 | 字段类型 | 字段说明 |
errcode | string | 0:消息发送成功 其他值:消息发送不成功 |
description | string | 结果或错误描述 |
data | array | 数据结果集 |
auth_code | string | 一次性授权码 |
expires_in | string | access_token的生命周期,单位是秒数。 |
(9)postman模拟调用
3.2、校验授权码
(1)接口路径
· https://api.cloudsz.kingdee.com/auth/user/auth_code/validation
·当获取到auth_code后,第三方应用可以通过该接口校验用户的有效性。
·auth_code在有效期内只能使用一次,当校验完后立即失效
(4)HTTP请求方式
·GET/POST
(5)返回格式
·JSON
(6)认证方式
·功能类API,使用client_id和client_secret认证
(7)请求参数
参数名称 | 必选 | 类型 | 说明 |
client_id | true | string | 应用ID |
client_secret | true | string | 应用secret |
auth_code | true | string | 用户授权码 |
参数名称 | 必选 | 类型 | 说明 |
(8)请求示例
https://api.cloudsz.kingdee.com/auth/user/auth_code/validation?client_id=[应用ID]&client_secret=[应用secret]&auth_code=1517b2e0d573ee7d9bc4a8b87c45cbce
(9)返回参数
返回参数 | 字段类型 | 字段说明 |
errcode | string | 1035:Invalid auth_code。1036:Forbidden using this auth_code |
description | string | 结果或错误描述 |
data | array | 数据结果集 |
uid | int | 用户ID |
nickname | string | 用户昵称 |
avatar | string | 用户头像 |
access_token | string | 用户的token |
expires_in | string | access_token的生命周期,单位是秒数。 |
source | int | 来源的应用ID |
(10)postman模拟调用
四、参考资料
云平台开发文档:https://cloud.kingdee.com/help/document/detail?item=14&doc=170
云平台测试环境:https://p.cloudsz.kingdee.com/
云平台正式环境:https://cloud.kingdee.com/
访问指定的数据中心:https://vip.kingdee.com/article/215788160662549248?productLineId=29
第三方集成单点登录:https://vip.kingdee.com/article/359709414254707456?productLineId=29
五、开发环境
V5.0.011
单点登录
本文2024-09-23 01:15:12发表“云苍穹知识”栏目。
本文链接:https://wenku.my7c.com/article/kingdee-cangqiong-144765.html
- 鼎捷EAI整合規範文件V3.1.07 (集團).pdf
- 鼎捷OpenAPI應用場景說明_基礎資料.pdf
- 鼎捷OpenAPI應用場景說明_財務管理.pdf
- 鼎捷T100 API設計器使用手冊T100 APIDesigner(V1.0).docx
- 鼎新e-GoB2雲端ERP B2 線上課程E6-2應付票據整批郵寄 領取.pdf
- 鼎新e-GoB2雲端ERP B2 線上課程A4使用者建立權限設定.pdf
- 鼎新e-GoB2雲端ERP B2 線上課程C3會計開帳與會計傳票.pdf
- 鼎新e-GoB2雲端ERP B2 線上課程E6-1應付票據.pdf
- 鼎新e-GoB2雲端ERP B2 線上課程A5-1進銷存參數設定(初階篇).pdf
- 鼎新e-GoB2雲端ERP B2 線上課程D2帳款開帳與票據開帳.pdf