概述

本模块介绍平台对第三方的单点登录集成说明,让开发人员可以更好进行集成单点认证。

整体认证流程

流程说明:

  1. 用户打开客户端若没有登录,则跳转到第三方登录认证页面;
  2. 用户输入令牌进行登录认证,登录成功,携带认证code码重新返回jpaas客户端;
  3. 客户端根据code通过后端jpaas服务器请求第三方获取认证的用户信息;
  4. 根据获取的第三方用户信息在jpaas进行登录;
  5. 登录成功则跳转到jpaas前端首页;

统一平台登录

用户打开客户端,客户端跳转到第三方登录认证页面

如上图所示,当访问jpaas平台登录页面时,识别是否存在第三方认证的code值,如果不存在则跳转到第三方登录认证页面进行单点登录,实现代码如下图所示:
代码实现:
跳转url解析:

jumpNewUrl(){
        var encoderContent = "https://****/authorize?response_type=code&scope=openid%20profile&client_id=****&state=coremail_stat&redirect_uri=http://****.com:8090";
        window.location.href = encoderContent;
      },
      casLogin(){
        var baseURL = process.env.VUE_APP_API_BASE_URL
        if(this.getQueryString('token') != null) {
          this.isLoading=false;
          var token = decodeURIComponent(this.getQueryString('token'));
          var key = decodeURIComponent(this.getQueryString('key'));
          Vue.ls.set(ACCESS_TOKEN, token, 12 * 60 * 60 * 1000)
          this.$store.commit('SET_TOKEN', token)

          this.$router.push({ name: 'index' }, () => {
            this.$notification.success({
              message: '欢迎',
              description: `${timeFix()},欢迎回来`
            })
          });
        }
        debugger;

        /**.vue
         * 下面的代码是测试单点登陆的代码,开发可以屏蔽
         */
        var wxOpenId = this.getDecodeURIQueryString('wxOpenId');
        var code =this.getDecodeURIQueryString('code');
        var state =this.getDecodeURIQueryString('state');
        //alert("--code="+code+"----state="+state);

        //如果企业微信存在,跳转到移动端页面
        if(wxOpenId){
          var encoderContent = "http://*****/mobile/#/pages/WxLogin?wxOpenId="+wxOpenId+"&zjWxCode="+code;
          window.location.href = encoderContent;
          return;
        }

        //开始浏览器输入地址时跳转
        if (!code && !state) {
          this.jumpNewUrl();
          return;
        }
        //debugger;
        //登录成功后回调
        if (code && state) {
          this.authorize(code);
          return;
        }
      },

登录认证

用户输入令牌进行登录认证,登录成功,携带认证code码重新返回jpaas客户端

如上图所示,在单点认证页面进行用户登录认证,登录成功,则根据上面的回调地址携带认证码code进行跳转回jpaas登录页面。

获取用户身份进行登录认证

客户端根据code通过后端jpaas服务器请求第三方获取认证的用户信息

jpaas根据获取到的认证code码,在jpaas平台后端服务器,根据与集成的第三方单点认证系统,通过接口协议传入code码获取当地登录用户信息。然后再jpaas平台进行登录。

代码实现:

@ApiOperation(value = "根据code免密登录")
    @GetMapping(SecurityConstants.PASSWORD_LOGIN_PRO_AUTHORIZE)
    public void authorize(@ApiParam(required = true, name = "code", value = "code") String code, HttpServletRequest request, HttpServletResponse response) throws IOException {
        log.error("---OAuth2Controller.authorize--根据code免密登录 code=" + code);
        String accessToken = ZhongTieJianUtil.getOauthToke(code);
        //使用HttpClient方式
        if (StringUtils.isEmpty(accessToken)) {
            returnFail(request, response,
                    "---OAuth2Controller.authorize--根据code免密登录 请求获取access_token错误-access_token is NULL");
            return;
        }
        String subStr = ZhongTieJianUtil.getHrOauthUserInfo(accessToken);
        if (StringUtils.isEmpty(subStr)) {
            returnFail(request, response, "---OAuth2Controller.authorize--根据code免密登录 获取用户信息-- sub is NULL");
            return;
        }
        String[] subList = subStr.split("[|]");
        String hrOgrKey = subList[0];
        //拦截非员工登录
        String providerI = SysPropertiesUtil.getString("hr.providerId");
        if (StringUtils.isEmpty(hrOgrKey) || !hrOgrKey.equals(providerI)) {
            returnFail(request, response, "---OAuth2Controller.authorize--当前用户非员工,不能登录");
            return;
        }
        String ztjUserId = subList[1];
        if (StringUtils.isEmpty(ztjUserId)) {
            returnFail(request, response, "---OAuth2Controller.authorize--根据code免密登录 userId is NULL");
            return;
        }
        OsUserDto user = orgService.getUserByZtjId(ztjUserId);
        if (BeanUtil.isEmpty(user) || StringUtils.isEmpty(user.getUserId())) {
            //用户不存在,为第一次登录,检查主岗位(或者父级,爷爷级组织)是否存在,不存在,通知对应管理员创建,否则新建用户和对应组织
            ResponseUtil.responseSucceed(objectMapper, response, "ztjUserId=" + ztjUserId+"=type="+ZtjHrQyApiUrl.ZTJ_CHANGE_TYPE_CREATE);
        } if(StringUtils.isEmpty(user.getMobile())){
            //已经存在用户,没有手机号需要短信验证
            ResponseUtil.responseSucceed(objectMapper, response, "ztjUserId=" + ztjUserId+"=type="+ZtjHrQyApiUrl.ZTJ_CHANGE_TYPE_EDIT);
        }else {
            //已经存在用户,检查用户组织是否有变更,并登录
            changeOrgToUsrAndLogin(request, response, user.getUserId());
        }
    }

    private void changeOrgToUsrAndLogin(HttpServletRequest request, HttpServletResponse response, String userId) {
        OsUserDto changeUser = orgService.changeOrgToUsrAndLogin(userId,"");
        try {
            //免密登录
            UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(changeUser.getAccount(), "");
            oAuth2Controller.writerToken(request, response, token, "登录失败", true);
        } catch (Exception e) {
            log.error("--changeOrgToUsrAndLogin is error:" + e.getMessage());
        }
    }    
    public void writerToken(HttpServletRequest request, HttpServletResponse response, AbstractAuthenticationToken token
            , String badCredenbtialsMsg, Boolean ignorePwd) throws IOException {
        try {
            OAuth2AccessToken oAuth2AccessToken = SecurityUtil.login(request, token, ignorePwd);
            ResponseUtil.responseSucceed(objectMapper, response, oAuth2AccessToken);
        } catch (BadCredentialsException | InternalAuthenticationServiceException e) {
            exceptionHandler(response, badCredenbtialsMsg);
        } catch (Exception e) {
            exceptionHandler(response, e);
        }
    }
文档更新时间: 2021-03-29 11:53   作者:zyg