十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

泛微Ecology9 SSO单点登录实战:Token获取与免登跳转全解析

泛微Ecology9 SSO单点登录实战:Token获取与免登跳转全解析 1. 项目概述Ecology9的SSO到底解决什么问题接手泛微Ecology9项目的人十有八九会碰到同一个需求公司上了OA但员工不可能天天打开OA网页再输一遍账号密码。大家习惯的是从企业微信、钉钉、HR系统、SAP、金蝶或者自研门户里点一下图标直接就进OA待办。这件事的学名叫单点登录英文简称SSO做得好不好直接影响OA的活跃度和口碑。这个实战项目围绕的核心链路很明确先通过泛微提供的集成接口换取Token再用Token拼出免登地址最后引导用户浏览器跳转完成从第三方系统到Ecology9的静默登录。整条链路不涉及改造泛微源码也不需要对Ecology9做侵入式开发完全是基于官方开放的认证接口来打通适合绝大多数企业OA集成场景。适合看这篇文章的人我大致划个范围一是要给公司OA做集成对接的Java开发二是负责OA运维、需要给业务系统开免登入口的实施顾问三是刚接触泛微生态、想搞清楚SSO原理的入门者。文章里我会把Token获取、签名计算、跳转URL组装、常见报错这些环节全部拆开讲每一步都给出能直接落地的方案而不是停留在概念层面。2. 核心原理Token从哪来、怎么用、怎么失效2.1 泛微Token体系拆解泛微Ecology9的SSO免登本质上是票据换登录态的机制。第三方系统先拿自己申请的集成身份AppId和SecretKey去泛微认证服务换一个临时Token这个Token相当于一张限时门票。拿到门票后拼接一个包含Token的免登链接用户浏览器一打开这个链接泛微服务端校验Token通过就在当前浏览器会话里种下登录态然后带着用户跳转到目标页面。把Token体系拆开看里面其实有几层。第一层是访问Token通过集成接口申请用来调用泛微的OpenAPI比如后续查流程、建待办都是用这个Token来鉴权。第二层是SSO Token专门用于免登跳转它的单次性和短时效决定了只能马上使用。第三层是服务端会话也就是用户浏览器和泛微之间建立的登录会话有这个会话存在用户才不会反复被踢回登录页。实操里最常见的误区是把这三个混为一谈。有人在后台拿到一个Token跳转失败之后反复调试同一个Token大部分情况就是Ticket已经消耗掉了。记住一个原则SSO场景下的Token是一次性的用完即焚别跟接口鉴权的Token搞混。2.2 申请Token的接口与签名规则泛微Ecology9对外提供了统一的认证接口不同版本路径略有差异但核心参数是一致的。以常用版本为例获取Token的接口大致是POST /api/ec/dev/auth/applytoken请求体为JSON格式大致如下{ appid: 你的集成应用ID, secretkey: 你的集成密钥, timestamp: 当前毫秒级时间戳, sign: 签名串 }签名串的计算不同项目里我见过两种常见规则。一种是直接把appid、secretkey、timestamp拼接后进行MD5另一种是把secretkey作为密钥对拼接内容做HMAC-SHA256。具体以泛微集成中心里配置的密钥生成方式为准但不管哪种签名的作用都是防止请求被篡改和重放。接口返回的内容里通常包含Token和过期时间{ code: 0, data: { token: xxxxxxxxxxxxx, expires: 300 } }这里的expires单位是秒默认一般是300秒。也就是说拿到Token之后必须在有效期内完成跳转过期就作废。如果你在泛微集成中心调整过Token有效期配置那以配置值为准。2.3 Token有效期与续期策略Token有效期决定了你在做集成时怎么写缓存。很多开发习惯把Token存到Redis里设置一个比实际有效略短的过期时间比如服务端返回300秒就设置成280秒。这样每次请求前先查Redis有就直接用没有就重新申请既减少了频繁调用认证接口的压力也避免Token在最后几秒失效时引发偶发登录失败。我见过一个项目因为Token缓存时间配置得跟服务端返回值一模一样导致一到临界点就会出现零星报错排查了大半个下午最后发现是缓存过期和Token服务端过期几乎同时发生请求打到服务端时刚好失效。这个坑不值得踩缓存过期时间刻意设置短一点多出来那几十秒不会对性能有任何明显影响。还有一点SSO跳转用的Token和OpenAPI调用用的Token能分开申请就分开申请。有些版本的泛微并不限制两个场景共用但分开之后互不干扰排障也更清晰。特别是对接多个第三方系统时每个系统一套集成身份出了问题可以快速定位是哪个系统在捣乱。3. 实操环节从Token获取到页面跳转的完整落地3.1 前置准备集成配置与密钥申请动手写代码之前必须在泛微系统里完成两件事。第一件事在泛微的集成中心有的版本叫集成平台、开放接口管理新增一个第三方应用拿到AppId和SecretKey。第二件事配置允许免登的域名或IP白名单确保第三方服务器调用认证接口不会被拒绝。需要注意泛微很多版本的接口调用会校验来源IP如果你们的OA跑在内网而第三方系统部署在其他网段要提前把出口IP加进白名单。曾经有个项目代码全部写完本地测试通过一上生产就报无权限访问最后发现是生产环境服务器的出口IP没加白名单。集成配置阶段还有两个容易被忽略的选项。一个是SSO免登开关有的版本需要单独开启才允许通过Token跳转免登另一个是Token的绑定模式你可以选择Token是否绑定用户这个决定了后面申请用户级Token时怎么传用户标识。3.2 后端获取Token的代码实现获取Token这段逻辑用Java写很直观大致流程是拼参数、算签名、发请求、解析响应、缓存Token。下面是简化后的代码示例注意生产环境里连接池、异常处理、配置项都要补全。/** * 泛微Token换取工具 */ public class WeaverTokenClient { private static final String AUTH_URL http://oa.example.com/api/ec/dev/auth/applytoken; private static final String APP_ID your-app-id; private static final String SECRET_KEY your-secret-key; /** * 计算签名具体算法以实际版本为准 */ private static String buildSign(String timestamp) { String raw APP_ID SECRET_KEY timestamp; return DigestUtils.md5Hex(raw); } /** * 申请Token */ public static String getToken() { String timestamp String.valueOf(System.currentTimeMillis()); MapString, String params new HashMap(); params.put(appid, APP_ID); params.put(secretkey, SECRET_KEY); params.put(timestamp, timestamp); params.put(sign, buildSign(timestamp)); // 使用HttpClient发送POST请求此处省略具体发送代码 String respBody HttpClientUtil.postJson(AUTH_URL, params); // 解析响应返回data.token return JsonUtil.parseToken(respBody); } }我这里把调用细节省略了实际写的时候要注意几个地方。一是timestamp必须用服务端时间不要用客户端本地时间服务器时间偏差超过允许范围会直接认证失败。二是发送请求时建议设置连接超时和读取超时泛微服务端偶尔会有慢查询默认超时时间不宜低于10秒。如果你想换取指定用户的免登Token有些版本提供了类似applytokenbyuser的接口多传一个loginname参数用来标识具体用户。这个场景在代用户发起待办、直接跳转办结的需求里非常实用比如HR系统替员工发起请假流程后可以直接跳到该员工的待办详情页。3.3 拼接跳转URL处理目标地址编码拿到Token并不是终点真正让用户免登成功的是最后那一次浏览器跳转。泛微的免登跳转地址格式大致如下http://oa.example.com/login/GetSSoToken.jsp?token你的Tokenurl跳转目标地址url参数填的是用户登录后想去的具体页面可以是PC端功能页也可以是移动端地址。这里有个很关键的细节url必须做URLEncoder编码否则遇到参数拼接符号、问号、中文字符时泛微服务端解析url会出问题跳转后落到错误页面甚至是白屏。String token getToken(); String target http://oa.example.com/wui/index.html; String redirectUrl http://oa.example.com/login/GetSSoToken.jsp ?token token url URLEncoder.encode(target, UTF-8);还有一种情况是目标地址本身还带有业务参数比如待办ID、流程实例ID这类地址编码时很容易漏掉。建议把完整的带参数地址先拼好再整串编码不要把url和参数分开处理否则参数到泛微服务端之后会被拆得七零八落。3.4 完整流程串联演示把整个链路串起来看一次成功的SSO跳转是这样的用户在企业门户点击进入OA按钮。门户后端收到请求后发现当前用户没有有效Token从缓存查询没有就申请。门户后端调用泛微Token换取接口拿到一次性Token。后端拼出带Token参数的免登地址直接返回302重定向响应给浏览器。浏览器跟随重定向带着Token访问泛微的GetSSoToken页面。泛微服务端校验Token合法建立会话再解析url参数跳转到目标页面。用户看到的是OA首页整个过程浏览器没有感知到登录过程。第4步这里我建议直接让后端返回302而不是把URL给前端让前端用window.location去跳。理由有两点一是302方式是服务端标准跳转更稳不会因为前端路由拦截导致Token暴露在历史记录里引发安全问题二是302响应在抓包调试时更清晰链路出问题能很快定位是后端拼URL的问题还是泛微校验的问题。如果采用的是前端先拿URL再跳转的方式务必在跳转前检查Token是否为空为空直接走异常提示页别让用户看到浏览器地址栏里一堆奇怪的参数。4. 踩坑实录高频问题与排查手册4.1 Token失效与签名报错签名错误是初次对接时最高频的问题。表现通常是调用认证接口直接返回失败错误信息类似sign校验不通过或者认证失败。排查方向上先确认签名算法是否和泛微版本匹配很多老版本用的是MD5拼接新版本却默认HMAC-SHA256接口文档不细看很容易踩雷。其次是AppId和SecretKey的归属。一个集成应用对应一套密钥拿A应用的密钥去调用B应用配置的接口权限大概率会出现鉴权失败。如果你们有多套环境测试环境、生产环境最容易出问题的就是密钥混用。我习惯在每个环境的配置中心单独建一套配置项严禁跨环境复用。Token失效问题也常见核心是排查Token到底是没拿到还是被消耗了。用一个临时脚本打日志把申请Token的响应原样打印出来重点看过期时间和响应码。跳转后再打一次日志看目标地址的响应状态如果返回的是登录页重定向说明Token校验没过如果返回的是404说明url参数编码或者拼接出了问题。4.2 页面跳转白屏、回登录页、死循环跳转白屏这个问题我见到的原因多到可以单独写一篇文章但排在本项目场景里的主要有两类。一类是url参数里的目标地址编码不完整泛微解析后拿到一个非法地址跳转到空白错误页。解决方法是把编码前的原始URL打出来手动检查是否有未编码的特殊字符。另一类是Token虽然通过了但目标页面所在的模块对当前用户没有权限页面加载后被重定向到一个空壳页面。回的登录页这个问题九成是Token已经过期或者被消耗剩下一成跟浏览器域名不匹配有关。你们OA的前台地址和后台跳转地址必须是同一个域名。曾经有个项目内网访问地址是IP加端口门户配置跳转却用了域名浏览器带着Token去访问域名地址因为域名解析出来根本不是同一台机器登录态自然丢失。还有一种相对隐蔽的死循环问题跳转URL里的目标地址本身又带了一个跳转逻辑比如指向某个需要二次鉴权的页面那个页面又跳回免登入口来回几次之后浏览器直接报重定向次数过多。这种情况要在目标地址的选择上做收敛OA侧能直达的页面就别再嵌套跳转逻辑。4.3 免登成功刷新后失效以及多系统互跳免登成功后用户如果长时间停留在某个页面不动session过期后再刷新会掉回登录页这个不完全是SSO的问题但用户感知是单点登录不稳定。泛微的会话超时时间可以在后端配置但更推荐的做法是在门户侧做一个轻量心跳定时刷新会话让用户感知不到会话断裂。注意心跳频率不要太激进否则会增加无效请求压力。多系统互跳的典型场景是从金蝶跳OA办完事又要跳回金蝶两边都是SSO。这里的关键是要各系统各自维护自己的Token不要在跳转过程中传递对方的TokenToken必须由持有密钥的后端系统换取后再跳。这种方案虽然多了一步但每个系统都能独立控制自己的安全边界排查问题时思路也清晰。多系统互跳里还有一个看似不起眼但非常磨人的坑目标地址的域名不统一。OA用的是oa.example.com门户用的是portal.example.com金蝶用的是erp.example.com。用户跳来跳去每跳一次浏览器都要重新建立cookiesession归属完全依赖域名免登是成功的但用户登录状态在三个域名之间互相不认。除非做统一的域名规划否则不要指望SSO能解决跨域会话共享该走统一门户中转就走统一门户中转。5. 经验总结与扩展方向5.1 实际操作中的几条心得这套SSO方案前前后后我在不同项目里落地过多次有个体会越来越深Token本身只是个技术凭证真正决定SSO体验的是跳转链路设计得是否干净。我最终沉淀的几条固定做法给你们作为参考。第一Token的申请动作一定要收敛到后端前端任何环节都不碰密钥。密钥一旦出现在前端代码里或者网络请求参数里就等于把家门钥匙挂在了门口。第二跳转地址统一走服务端302不用前端路由跳转少一层暴露面。第三每个第三方系统一套集成密钥出了问题可以精准定位是哪个系统在刷Token。第四日志一定要打全申请Token请求和响应、跳转URL、目标页面响应码这三条日志缺一不可。很多隔空排查的难题最后都是靠日志定位到的。缓存设计上强烈建议给Token单独建一个Redis缓存键过期时间设置成服务端返回值的80%到90%具体公式就是Redis过期时间 服务端Token有效期 - 提前量建议10~30秒这样可以避免临界点上的偶发失效。如果集成系统多、调用量上来了还可以做本地内存缓存加Redis二级缓存的结构本地没命中再去查RedisRedis没有再去调泛微接口三层下来性能基本不会成为瓶颈。5.2 可以继续扩展的方向基础SSO打通之后可以根据业务需要继续向两个方向延展。一个方向是单点登出用户在门户退出登录时同步调用泛微的会话失效接口把OA侧的会话一起清理掉。这个在合规审计比较严格的企业里几乎是标配不然用户以为退出了OA的会话还挂着存在安全隐患。另一个方向是待办集成。SSO解决的是能进OA的问题待办集成解决的是进了OA直接看到自己要做的事的问题。通过泛微的待办推送接口可以把第三方系统的审核任务主动推到OA待办中心用户点待办直接跳转到对应处理页面。这个方向比单纯的SSO更有业务价值但复杂度也上了一个台阶涉及待办标题、链接、业务标识的回传设计。具体的接口差异不同版本、不同授权可能会有出入动手之前先在测试环境把官方接口文档完整过一遍配合抓包工具确认请求和响应结构比直接看网上的代码片段要稳得多。我的经验是泛微的接口体系相当庞大但核心路径都是通的只要抓住Token换取和免登跳转这两个支点SSO这件事就算拿下了八成。剩下两成就是踩过坑之后形成的排错手感和对业务场景的理解了。
返回列表