苍穹页面触发 | 在新浏览器窗口打开第三方带会话信息页面

栏目:云苍穹知识作者:金蝶来源:金蝶云社区发布:2024-09-23浏览:1

苍穹页面触发 | 在新浏览器窗口打开第三方带会话信息页面

# 关键词:页面跳转、单点登录、跳转第三方系统页面 # 一、需求 苍穹与第三方系统页面集成。用户登录苍穹之后,在页面上点击某个控件之后,系统自动单点登录并以新的浏览器窗口打开第三方系统的指定页面,然后用户可自由进行业务操作。 # 二、思路与方案 从苍穹页面以新浏览器窗口跳转第三方系统页面,有多种实现方式,如:点击超链接、点击工具栏按钮、点击标签控件等,并在相应的事件中通过 this.getView().openUrl(String) 达到目标。 有关单点登录,社区已存在许多很成熟的方案,可自行参阅相关资料开发即可。 # 三、实现过程 ## 3.1 准备工作 苍穹系统:http://172.20.14.30:8080/ierp 第三方系统:本案例以另一套苍穹环境进行模拟,其访问地址:http://172.20.240.127:8080/ierp 统一身份认证服务系统:https://api.kingdee.com ## 3.2 注册应用 登录金蝶云平台注册应用,设置回调地址为苍穹系统的IP&端口,用于苍穹系统登录认证 *备注: 如需复现案例效果,请自行前往金蝶云平台注册应用后,配置回调地址,并修改 Parameter.java & CloudPlatformSSOAuth.java 文件中 CLIENT_ID & CLIENT_SECRET 的值。* ![云平台应用-苍穹.webp](/download/0100cbd0027effde4027a0b09e3f3d80cea3.webp) ## 3.3 在苍穹系统中开发单点登录金蝶云平台插件(CldPlatformSSOPlugin) 1.先判断系统是否登录,若没有,则返回;若已登录,则根据金蝶云平台返回的授权码获取access_token,再获取用户信息进行认证,认证成功则登录苍穹系统。 ```language @Override public UserAuthResult getTrdSSOAuth(HttpServletRequest request, HttpServletResponse response) { UserAuthResult result = new UserAuthResult(); result.setSucess(false); // 判断是否成功登录金蝶云平台, 通过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(KEY_CACHE_SSOLOGIN); String infoStr = cache.get(state); JSONObject paramObj; if (StringUtils.isNotEmpty(infoStr)) { paramObj = JSONObject.parseObject(infoStr); } else { paramObj = new JSONObject(); } // 重定向到指定页面 String queryParam = paramObj.getString("queryparam"); if (!request.getQueryString().contains("flag=1")) { try { String url = String.format("%1$s/?code=%2$s&state=%3$s&flag=1", Parameter.COSMIC_HOME_URL, code, URLEncoder.encode(state, "UTF-8")); if (StringUtils.isNotEmpty(queryParam)) { url = String.format("%1$s&%2$s", url, queryParam); } response.sendRedirect(url); } catch (Exception e) { logger.error(String.format("重定向失败: %s", ExceptionUtils.getExceptionStackTraceMessage(e))); } return result; } // 从云平台获取access_token JSONObject responseObj = SSOUtil.getAccessToken(code); Integer errCode = responseObj.getInteger("errcode"); String accessToken = null; if (errCode != null && errCode == 0) { accessToken = responseObj.getJSONObject("data").getString("access_token"); request.setAttribute("kdcloudaccesstoken", accessToken); } else { String errDesc = StringUtils.isEmpty(responseObj.getString("description")) ? "未获取到access_token信息!" : responseObj.getString("description"); result.setErrDesc(errDesc); logger.error(errDesc); return result; } // 从云平台获取登录用户基本信息 JSONObject userInfoObj = SSOUtil.getUserInfo(accessToken); errCode = userInfoObj.getInteger("errcode"); if (errCode != null && errCode == 0) { JSONObject data = userInfoObj.getJSONObject("data"); result.setUser(data.getString("phone")); result.setUserType(UserProperType.Mobile); result.setSucess(true); } else { String errDesc = StringUtils.isEmpty(userInfoObj.getString("description")) ? "未查询到用户信息!" : userInfoObj.getString("description"); logger.error(errDesc); throw new KDException(LoginErrorCode.loginBizException, "系统错误,请联系系统管理员。" + errDesc); } return result; } ``` 2.若用户未登录,则跳转到金蝶云平台的登录页,成功登陆之后系统重定向到苍穹系统门户首页。若用户退出系统、或者再次访问之前已登录的地址,则通过重定向到苍穹默认登录页转而重定向到金蝶云平台的登录页。 ```language @Override public void callTrdSSOLogin(HttpServletRequest request, HttpServletResponse response, String backUrl) { // 退出处理 if (request.getRequestURI().contains("logout.do")) { this.logout(request); this.sendRedirect(response, Parameter.COSMIC_HOME_URL); return; } if (!response.isCommitted()) { // 用户未登录, 且访问链接包含以前请求的code & state 参数, 则重定向到本系统的homeUrl发起访问 String code = request.getParameter("code"); String state = request.getParameter("state"); if (StringUtils.isNotEmpty(code) && StringUtils.isNotEmpty(state)) { this.sendRedirect(response, Parameter.COSMIC_HOME_URL); return; } } // sso插件重定向处理 if (request.getQueryString() != null && request.getQueryString().contains("flag=1")) { return; } // 正常登录访问苍穹,构造缓存数据 String state = ID.genStringId(); DistributeSessionlessCache cache = CacheFactory.getCommonCacheFactory().getDistributeSessionlessCache(KEY_CACHE_SSOLOGIN); JSONObject paramObj = new JSONObject(); paramObj.put("queryparam", request.getQueryString()); cache.put(state, JSONObject.toJSONString(paramObj), 60); // 根据sso地址构造,登录地址 重定向到云平台 try { // 成功登录之后重定向到系统门户首页 String redirectUri = String.format("%1$s%2$s", Utils.getHomeUrl(Parameter.COSMIC_HOME_URL), "index.html"); String url = String.format("%1$s?client_id=%2$s&response_type=%3$s&redirect_uri=%4$s&state=%5$s", String.format("%1$s%2$s", Utils.getHomeUrl(Parameter.AUTH_CENTER_URL), "auth/oauth2/authorize"), Parameter.CLIENT_ID, "code", URLEncoder.encode(redirectUri, "UTF-8"), URLEncoder.encode(state, "UTF-8")); response.sendRedirect(url); } catch (IOException e) { logger.error(String.format("重定向失败: %s", ExceptionUtils.getExceptionStackTraceMessage(e))); } } ``` 3.成功登陆之后,将 access_token 放入分布式缓存中,后续在跳转第三方系统页面时使用。 ```language @Override public void processSucceedLogin(HttpServletRequest request, String globalSessionId) { // 将从金蝶云平台获取的 access_token 存入分布式缓存, 1天有效期. 后续跳转第三方系统页面时取出使用 String accessToken = (String) request.getAttribute("kdcloudaccesstoken"); DistributeSessionlessCache cache = CacheFactory.getCommonCacheFactory().getDistributeSessionlessCache(KEY_CACHE_SSOLOGIN); cache.put(globalSessionId, "kdcloudaccesstoken", accessToken, 1 * 24 * 60 * 60); ThirdSSOAuthHandler.super.processSucceedLogin(request, globalSessionId); } ``` ## 3.4 点击页面上控件后单点登录并跳转第三方系统页面 ### 1.点击控件在新浏览器窗口跳转第三方系统页面 #### 方式一:点击工具栏按钮跳转 ```language @Override public void itemClick(ItemClickEvent evt) { String itemKey = evt.getItemKey(); if (StringUtils.equalsIgnoreCase(KEY_BARITEM_TOTRDSYSPAGE, itemKey)) { this.openTrdSysPage(); } super.itemClick(evt); } ``` #### 方式二:点击超链接控件跳转 页面打开时为超连接控件设置待打开第三方系统页面URL。 ```language @Override public void afterBindData(EventObject e) { String targetUrl = this.getTrdSysTargetUrl(); // 为超链接控件设置url Hyperlink toTrdSysHyperlink = this.getView().getControl(KEY_HYPERLINK_TOTRDSYSPAGE); toTrdSysHyperlink.setUrl(targetUrl); super.afterBindData(e); } ``` #### 方式三:点击标签控件跳转 *备注: 必须先对标签控件添加点击监听。* ```language @Override public void registerListener(EventObject e) { // 对标签控件添加点击监听 this.addClickListeners(KEY_LABEL_TOTRDSYSPAGE); super.registerListener(e); } @Override public void click(EventObject evt) { Control control = (Control) evt.getSource(); String key = control.getKey(); if (StringUtils.equalsIgnoreCase(KEY_LABEL_TOTRDSYSPAGE, key)) { this.openTrdSysPage(); } super.click(evt); } ``` ```language /** * 跳转第三方系统页面 */ private void openTrdSysPage() { this.getView().openUrl(this.getTrdSysTargetUrl()); } ``` ### 2.在上一步插件中实现业务逻辑:苍穹系统单点登录第三方系统 *备注: 本案例以另一套苍穹系统模拟第三方系统,分别实现了跳转第三方系统(苍穹)的系统门户首页 & 第三方系统(苍穹)中币别列表界面。 本案例通过配置应用参数实现点击不同的应用卡片跳转不同的链接,有关应用参数的开发请参阅参考资料,此处不做详述。* ```language /** * 获取待访问的第三方系统页面(带登录信息) * @return */ private String getTrdSysTargetUrl() { DistributeSessionlessCache cache = CacheFactory.getCommonCacheFactory().getDistributeSessionlessCache("ssoLogin"); String accessToken = cache.get(RequestContext.get().getGlobalSessionId(), "kdcloudaccesstoken"); if (StringUtils.isEmpty(accessToken)) { logger.error("系统从金蝶云平台获取授权码(auth_code)时access_token为空!"); this.getView().showErrorNotification("请重新登录系统!"); return null; } // 单点登录成功之后打开第三方系统门户首页 String trdSysTargetUrl = OpenTrdPageUtils.getTrdSysHomeUrl("kdec_tstapp2"); if (StringUtils.isEmpty(trdSysTargetUrl)) { logger.error("系统参数为空!"); this.getView().showMessage("系统配置不完善, 请联系系统管理员操作!"); return null; } // 单点登录成功之后打开第三方指定页面(此处以币别列表界面为例) // trdSysTargetUrl = String.format("%1$s%2$s", trdSysTargetUrl, "index.html?billFormId=bd_currency&formId=bos_list"); if (StringUtils.isNotEmpty(accessToken)) { String authCode = SSOUtil.getAuthCode(accessToken); // 如果可从金蝶云平台获取到auth_code, 则系统自动单点登录到第三方系统页面; 否则需用户手动登录 if (StringUtils.isNotEmpty(authCode)) { String tmpStr = trdSysTargetUrl.endsWith("/") ? "?" : "&"; trdSysTargetUrl = String.format("%1$s%2$sauth_code=%3$s", trdSysTargetUrl, tmpStr, authCode); } } return trdSysTargetUrl; } ``` ## 3.5 在第三方系统中开发单点登录金蝶云平台插件(CloudPlatformSSOAuth) *备注: 1.考虑到不同项目、产品的第三方系统各不相同,此处代码仅作参考。 2.该案例代码控制第三方系统只能从苍穹登录后再跳转,即使访问第三方系统登录页也会重定向到苍穹系统的默认访问地址。* ```language @Override public void callTrdSSOLogin(HttpServletRequest request, HttpServletResponse response, String backUrl) { // 将第三方系统(即:本苍穹系统)登录&退出请求, 全部重定向到苍穹系统的默认访问地址 this.sendRedirect(response, COSMIC_HOME_URL); return; } @Override public UserAuthResult getTrdSSOAuth(HttpServletRequest request, HttpServletResponse response) { UserAuthResult result = new UserAuthResult(); result.setSucess(false); String responseStr = null; // 根据 auth_code 判断是否为外部系统登录本系统 String authCode = request.getParameter("auth_code"); if (StringUtils.isNotEmpty(authCode)) { // 从外部系统登录 try { String url = String.format("%1$s%2$s", getHomeUrl(AUTH_CENTER_URL), "auth/user/auth_code/validation"); Map<String, Object> body = new HashMap<>(); body.put("client_id", CLIENT_ID); body.put("client_secret", CLIENT_SECRET); body.put("auth_code", authCode); responseStr = HttpClientUtils.post(url, null, body); } catch (IOException e) { logger.error("校验授权码失败: %s", ExceptionUtils.getExceptionStackTraceMessage(e)); } } else { return result; } JSONObject responseObj = StringUtils.isNotEmpty(responseStr) ? JSONObject.parseObject(responseStr) : new JSONObject(); Integer errCode = responseObj.getInteger("errcode"); if (errCode != null && errCode == 0) { String accessToken = responseObj.getJSONObject("data").getString("access_token"); try { String url = String.format("%1$s%2$s?access_token=%3$s", getHomeUrl(AUTH_CENTER_URL), "account/user_info", accessToken); responseStr = HttpClientUtils.get(url); } catch (Exception e) { logger.error("查询用户信息出错: %s", ExceptionUtils.getExceptionStackTraceMessage(e)); } JSONObject userInfoObj = StringUtils.isNotEmpty(responseStr) ? JSONObject.parseObject(responseStr) : new JSONObject(); errCode = userInfoObj.getInteger("errcode"); if (errCode != null && errCode == 0) { String phone = userInfoObj.getJSONObject("data").getString("phone"); result.setUser(phone); result.setUserType(UserProperType.Mobile); result.setSucess(true); } else { String errDesc = StringUtils.isEmpty(responseObj.getString("description")) ? "未获取到用户信息!" : responseObj.getString("description"); throw new KDException(LoginErrorCode.loginBizException, String.format("系统错误,请联系系统管理员。%s", errDesc)); } } else { String errDesc = StringUtils.isEmpty(responseObj.getString("description")) ? "未获取到access_token信息!" : responseObj.getString("description"); result.setErrDesc(errDesc); logger.error(errDesc); } return result; } ``` # 四、效果图 ## 4.1 登录苍穹系统 ![苍穹登录.webp](/download/01003b5998b4c6ef460b9a308619c672a00c.webp) ![云平台登录页-1.webp](/download/010075f85fc05d71419d9a3f632a12a9f3a7.webp) ## 4.2 点击控件跳转页面 ![苍穹页面.webp](/download/0100391b7203857d49479d027427e399e01e.webp) ## 4.3 第三方系统 ![第三方系统-门户首页.webp](/download/01001cf6ba051a974e63be0a3358f6e98ac4.webp) ![第三方系统-币别列表.webp](/download/0100708fbb974c414a66ae8c85bfe8b229a3.webp) # 五、开发环境版本 V5.0.011 # 六、注意事项 - 在开发单点登录功能前,需先同步苍穹与第三方系统的人员数据,使其保持一致(组织数据可根据实际业务确定)。考虑该功能点可独立开发,本案例中不予实现。 - 需调整第三方系统前端界面UI与苍穹保持一致。 - 如需复现本案例效果,必须先在金蝶云平台注册应用并修改案例代码中的相关参数,详见第$3.2节-注册应用。 - 附件中包含案例所有页面元数据、Java源码,如有需要,请自行下载。 # 七、参考资料 [开发平台](https://vip.kingdee.com/knowledge/specialDetail/218022218066869248?productLineId=29) [学习成长中心](https://developer.kingdee.com/school?productLineId=29) [登录认证专题](https://vip.kingdee.com/knowledge/specialDetail/228892721203874816?productLineId=29) [苍穹产品目录](https://developer.kingdee.com/knowledge?productLineId=29#tabMain) —— 系统服务云 —— 系统管理 —— 登录认证 [单点登录集成](https://developer.kingdee.com/school/243812482044022016?productLineId=29)(视频) [使用SSO时启用账密登录功能介绍](https://developer.kingdee.com/article/329216123843848960?productLineId=29&isKnowledge=2) [金蝶云平台oauth2流程说明](https://cloud.kingdee.com/help/document/detail?item=448&doc=3023) [【统一身份认证】第三方集成单点登录](https://developer.kingdee.com/article/359709414254707456?share_fromuid=&productLineId=29&islogin=true)

如何在苍穹页面上跳转并单点登录第三方系统页面.zip

苍穹页面触发 | 在新浏览器窗口打开第三方带会话信息页面

# 关键词:页面跳转、单点登录、跳转第三方系统页面# 一、需求苍穹与第三方系统页面集成。用户登录苍穹之后,在页面上点击某个控件之后,...
点击下载文档
确认删除?
回到顶部
客服QQ
  • 客服QQ点击这里给我发消息