# 单点登录集成

# 说明

参考 第三方工具API集成

# 后端开发

实现单点登录平台token校验接口

实现单点登录平台获取登录用户信息接口

改造JwtTokenService

  • 新增ssoToken校验方法
    //示例方法
    private void checkSsoToken(HttpServletRequest request, HttpServletResponse response) throws Exception {
		DataContextThreadLocal dataContextThreadLocal = DataContextThreadLocal.current();
		String token = request.getHeader(Constants.AUTHORIZATION_HEAD_KEY);
        //单点登录平台token校验
		Map validateInfo = ssoService.validateSsoToken(token);
		if (validateInfo == null) {
			throw new DevOpsException(DevOps.PCM.SSO_TOKEN_VALIDATE_FAILED, token, "");
		}
		if (StringUtils.equals(validateInfo.get("result") + "", "error")) {
			throw new DevOpsException(DevOps.PCM.SSO_TOKEN_VALIDATE_FAILED, token, validateInfo.get("rsltmsg"));
		}
		response.setHeader(Constants.AUTHORIZATION_HEAD_KEY, token);
        //单点登录平台获取登录用户信息
		Map userInfo = ssoService.getSsoUserInfo(token);
		if (userInfo == null) {
			throw new DevOpsException(DevOps.PCM.SSO_GET_USER_INFO_BY_TOKEN_ERROR, token);
		}
        //获取单点登录平台登录用户的用户名
		String userName = userInfo.get("account") + "";
        //查询DevOps本地用户是否存在
		User user = userService.getUserFromDb(userName);
		if (user == null) {
			throw new DevOpsException(DevOps.UC.USER_NOT_EXISTED, userName);
		}
		dataContextThreadLocal.setUserInfo(user.getEmployee().getEmpId(), userName, user.getEmployee().getEmpName(), user.getTenantId());
		dataContextThreadLocal.setToken(token);
	}

  • 替换原有本地token校验方法

# 前端开发

实现单点登录平台登录流程

  • 将跳转链接转成符合DevOps规则的链接
 //src/before.js
 //本地登录流程链接中需要加入‘login’
  //示例 (根据平台跳转链接来修改)
    else if (window.location.href.indexOf('access_token') !== -1 && window.location.href.indexOf('login') === -1) {
      window.location.href = `http://${window.location.host}/#/login?${window.location.hash.slice(3)}`
      window.location.reload()
      next()
    }
  • 根据token获取用户信息
 //示例 src/views/login/index.vue
  //判断是否是其它平台跳转
    mounted() {
    //若登录密码修改规则由所属平台决定,则此处需要存入'是否需要修改密码'为否
    store.set('needChangePassword', false)
	//根据跳转的地址来获取token
    let token = null
    if (location.href.includes('?') && location.href.includes('access_token')) {
      let params = location.href.split('?')[1]
      params = params.split('&')
      params.forEach(p => {
        if (p.includes('access_token')) {
          token = p.split('=')[1]
        }
      })
    }
    if (token) {
      this.getCurrentUser(token)
    } else if (getLoginType()) {
      this.loginType = getLoginType()
    } else {
      this.loadData()
    }
	},
 //示例 src/views/login/index.vue
  //根据token获取用户个人信息
  //获取成功则进入下一阶段,否则跳转回原平台
    async getCurrentUser(token) {
      const ajaxBody = {
        url: 'api/uc/users/current-user',
        method: 'get',
      }
      AjaxUtil.headers({
        Authorization: token,
      })
        .ajax({
          ...ajaxBody
        }).then(resp => {
          const userInfo = {
            data: {
              ..._.cloneDeep(resp.data.employee),
              token: token,
            }}
          this.loginSuccess(userInfo)
        }).catch(resp => {
          this.getSsoAddress()
        })
    },
  • 不退出时登录其它账号先清除之前储存的token
 //示例 src/views/login/index.vue
  if ((to.path === '/login' && to.query.token) || (window.location.href.indexOf('access_token') !== -1 && window.location.href.indexOf('login') === -1)) {
    // 如果路由为login且带有token参数,自动删除缓存中的token重新登录
    // 如果url带有token,自动删除缓存中的token重新登录
    removeToken()
  }
  • 退出DevOps
 //直接退出
 //src/views/layout/components/Navbar.vue
  logout() {
      const loginType = getLoginType()
      if (loginType === 'IAM') {
        this.iamLogout()
      } else {
        this.getSsoAddress()
      }
    },
//获取到返回的地址
    async getSsoAddress() {
      const resp = await this.dispatch(
        ISsoController.getSsoAddress, {
        }
      )
      if (!resp.error) {
        if (resp.data) {
          this.$store.dispatch('LogOut').then(() => {
            window.location.href = resp.data
          })
        } else {
          this.$store.dispatch('LogOut').then(() => {
            this.$router.push({ name: 'login' })
          })
        }
      }
    },
//token过期退出
//src/libs/VueUtil.js
 this.logout = () => {
    if (window.DEVOPS_BACK_TO_LOGIN) {
      clearTimeout(window.DEVOPS_BACK_TO_LOGIN)
    }
    $this.$store.dispatch('FedLogOut').then(async() => {
      if ($this.$route.name !== 'login') {
        store.set('preUrl', window.location.href)
        const resp = await this.dispatch(ISsoController.getSsoAddress)
        if (!resp.error) {
          if (resp.data) {
            window.location.href = resp.data
          } else {
            $this.$router.push('/login')
          }
        }
        this.getConfigParamValue()
        window.location.reload()
      }
    })
  }
上次更新: 2023-4-11 15:41:03