# 单点登录集成
# 说明
参考 第三方工具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()
}
})
}
← 前端集成开发 工作项流程处理类拓展 →