钉钉SSO单点登录机制
1. login页面在生命周期函数中调用ssoAuth
得到钉钉临时授权token
export default function ssoAuth() {
const login = `${window.location.origin}/login`;
window.location.assign(`https://sso-test.com/auth?redirect=${encodeURIComponent(login)}`);
}
// 如果当前页面是localhost:3100,调用ssoAuth就返回
// http://localhost:3100/login?token=1F15J6lAlW4Snafna7c5y7568UWHXN3QEMEe03jyg212E
// 也就是重新定向到sso登录页面 此时页面路由上携带一个有时效的临时token
2.在路由上拿到临时token,调用服务器接口换取jwt
和用户信息
const { token } = route.query;
const { jwt, ...userInfo } = await ssoDingLoginApi(token);
3.将jwt存到cookie中
function setToken(jwt: string) {
// 兼容本地调试
if (location.host.includes('localhost')) {
Cookies.set(TOKEN_KEY, jwt);
}
// domain建议使用一级域名,这样子级其他域名也能自带cookie
Cookies.set(TOKEN_KEY, jwt, { domain: 'xxx.com' });
}
setToken(jwt)
4.在axios请求拦截器中加入jwt
function getToken() {
return Cookies.get(TOKEN_KEY) || '';
}
const HEAD_TOKEN = 'X-Token'; // 和服务器约定放jwt的字段
/**
* @description: 请求拦截器处理
*/
const requestInterceptors = (config, _options) => {
const token = getToken();
if (token) {
config.headers[HEAD_TOKEN] = token;
}
return config;
},
5.发送获取全局信息接口诸如权限配置等,并跳转到首页
在首页可以正常调用接口
router.replace(PageEnum.BASE_HOME);
6.jwt异常处理
- jwt过期或者无效的处理,在axios响应拦截器中统一处理;
- 如果遇到特定的表示需要重新登录的code,就做统一退出处理,重定向到login页面;
- login页面自动调用
ssoAuth
重复从1到5的过程;
/**
* @description: 响应错误处理
*/
const responseInterceptorsCatch: (error: any) => {
checkStatus(error?.response?.status, msg, errorMessageMode);
return Promise.reject(error);
},
const checkStatus(status, msg, errorMessageMode) => {
switch(status) {
case 401:
if (stp === SessionTimeoutProcessingEnum.PAGE_COVERAGE) {
userStore.setToken('');
userStore.setSessionTimeout(true);
} else {
userStore.logout(true);
}
break;
}
}
async logout(goLogin = false) {
this.setToken('');
this.setSessionTimeout(false);
router.push(PageEnum.BASE_LOGIN);
}
自此结束