201 lines
5.0 KiB
TypeScript
201 lines
5.0 KiB
TypeScript
import request from '/@/utils/request';
|
||
import { Session } from '/@/utils/storage';
|
||
import { validateNull } from '/@/utils/validate';
|
||
import { useUserInfo } from '/@/stores/userInfo';
|
||
import other, { sm2Encrypt } from '/@/utils/other';
|
||
|
||
/**
|
||
* https://www.ietf.org/rfc/rfc6749.txt
|
||
* OAuth 协议 4.3.1 要求格式为 form 而不是 JSON 注意!
|
||
*/
|
||
const FORM_CONTENT_TYPE = 'application/x-www-form-urlencoded';
|
||
|
||
/** 登录是否使用 SM2 加密密码(需后端配置 SM2 私钥并支持 Enc-Flag: sm2) */
|
||
const LOGIN_SM2_ENABLE = import.meta.env.VITE_LOGIN_SM2_ENABLE === 'true';
|
||
/** SM2 公钥(十六进制,与后端私钥成对),用于前端加密密码 */
|
||
const SM2_PUBLIC_KEY = import.meta.env.VITE_SM2_PUBLIC_KEY || '';
|
||
|
||
// 登录方式
|
||
export enum LoginTypeEnum {
|
||
PASSWORD,
|
||
MOBILE,
|
||
REGISTER,
|
||
EXPIRE,
|
||
QRCODE,
|
||
}
|
||
|
||
// 登录错误信息
|
||
export enum LoginErrorEnum {
|
||
CREDENTIALS_EXPIRED = 'credentials_expired', // 密码过期
|
||
}
|
||
|
||
/**
|
||
* 社交登录方式枚举
|
||
*/
|
||
export enum SocialLoginEnum {
|
||
SMS = 'SMS', // 验证码登录
|
||
DINGTALK = 'DINGTALK', // 钉钉
|
||
WEIXIN_CP = 'WEIXIN_CP', // 企业微信
|
||
APP_SMS = 'APP-SMS', // APP验证码登录
|
||
QQ = 'QQ', // QQ登录
|
||
WECHAT = 'WX', // 微信登录
|
||
MINI_APP = 'MINI', // 微信小程序
|
||
GITEE = 'GITEE', // 码云登录
|
||
OSC = 'OSC', // 开源中国登录
|
||
CAS = 'CAS', // CAS 登录
|
||
}
|
||
|
||
/**
|
||
* 登录
|
||
* @param data
|
||
*/
|
||
export const login = (data: any) => {
|
||
const basicAuth = 'Basic ' + window.btoa(import.meta.env.VITE_OAUTH2_PASSWORD_CLIENT);
|
||
Session.set('basicAuth', basicAuth);
|
||
let encPassword: string;
|
||
let encFlag: string;
|
||
if (LOGIN_SM2_ENABLE && SM2_PUBLIC_KEY) {
|
||
encPassword = sm2Encrypt(data.password, SM2_PUBLIC_KEY);
|
||
encFlag = 'sm2';
|
||
} else {
|
||
encPassword = other.encryption(data.password, import.meta.env.VITE_PWD_ENC_KEY);
|
||
encFlag = 'false';
|
||
}
|
||
const { username, randomStr, code, grant_type, scope } = data;
|
||
return request({
|
||
url: '/auth/oauth2/token',
|
||
method: 'post',
|
||
params: { username, randomStr, code, grant_type, scope },
|
||
data: { password: encPassword },
|
||
headers: {
|
||
skipToken: true,
|
||
Authorization: basicAuth,
|
||
'Content-Type': FORM_CONTENT_TYPE,
|
||
'Enc-Flag': encFlag,
|
||
},
|
||
});
|
||
};
|
||
|
||
export const loginByMobile = (mobile: any, code: any) => {
|
||
const grant_type = 'mobile';
|
||
const scope = 'server';
|
||
const basicAuth = 'Basic ' + window.btoa(import.meta.env.VITE_OAUTH2_MOBILE_CLIENT);
|
||
Session.set('basicAuth', basicAuth);
|
||
|
||
return request({
|
||
url: '/auth/oauth2/token',
|
||
headers: {
|
||
skipToken: true,
|
||
Authorization: basicAuth,
|
||
'Content-Type': FORM_CONTENT_TYPE,
|
||
},
|
||
method: 'post',
|
||
params: { mobile: `${SocialLoginEnum.SMS}@${mobile}`, code: code, grant_type, scope },
|
||
});
|
||
};
|
||
|
||
export const loginBySocial = (state: SocialLoginEnum, code: string) => {
|
||
const grant_type = 'mobile';
|
||
const scope = 'server';
|
||
const basicAuth = 'Basic ' + window.btoa(import.meta.env.VITE_OAUTH2_SOCIAL_CLIENT);
|
||
Session.set('basicAuth', basicAuth);
|
||
|
||
return request({
|
||
url: '/auth/oauth2/token',
|
||
headers: {
|
||
skipToken: true,
|
||
Authorization: basicAuth,
|
||
'Content-Type': FORM_CONTENT_TYPE,
|
||
},
|
||
method: 'post',
|
||
params: { mobile: `${state}@${code}`, code: code, grant_type, scope },
|
||
});
|
||
};
|
||
|
||
export const sendMobileCode = (mobile: string) => {
|
||
return request({
|
||
url: '/admin/sysMessage/send/smsCode',
|
||
method: 'get',
|
||
params: { mobile },
|
||
});
|
||
};
|
||
|
||
export const refreshTokenApi = (refresh_token: string) => {
|
||
const grant_type = 'refresh_token';
|
||
const scope = 'server';
|
||
// 获取当前选中的 basic 认证信息
|
||
const basicAuth = Session.get('basicAuth');
|
||
|
||
return request({
|
||
url: '/auth/oauth2/token',
|
||
headers: {
|
||
skipToken: true,
|
||
Authorization: basicAuth,
|
||
'Content-Type': FORM_CONTENT_TYPE,
|
||
},
|
||
method: 'post',
|
||
params: { refresh_token, grant_type, scope },
|
||
});
|
||
};
|
||
|
||
/**
|
||
* 校验令牌,若有效期小于半小时自动续期
|
||
* @param refreshLock
|
||
*/
|
||
export const checkToken = (refreshTime: number, refreshLock: boolean) => {
|
||
const basicAuth = Session.get('basicAuth');
|
||
request({
|
||
url: '/auth/token/check_token',
|
||
headers: {
|
||
skipToken: true,
|
||
Authorization: basicAuth,
|
||
'Content-Type': FORM_CONTENT_TYPE,
|
||
},
|
||
method: 'get',
|
||
params: { token: Session.getToken() },
|
||
})
|
||
.then((response) => {
|
||
if (validateNull(response) || response.code === 1) {
|
||
clearInterval(refreshTime);
|
||
return;
|
||
}
|
||
const expire = Date.parse(response.data.expiresAt);
|
||
if (expire) {
|
||
const expiredPeriod = expire - new Date().getTime();
|
||
//小于半小时自动续约
|
||
if (expiredPeriod <= 30 * 60 * 1000) {
|
||
if (!refreshLock) {
|
||
refreshLock = true;
|
||
useUserInfo()
|
||
.refreshToken()
|
||
.catch(() => {
|
||
clearInterval(refreshTime);
|
||
});
|
||
refreshLock = false;
|
||
}
|
||
}
|
||
}
|
||
})
|
||
.catch(() => {
|
||
// 发生异常关闭定时器
|
||
clearInterval(refreshTime);
|
||
});
|
||
};
|
||
|
||
/**
|
||
* 获取用户信息
|
||
*/
|
||
export const getUserInfo = () => {
|
||
return request({
|
||
url: '/admin/user/info',
|
||
method: 'get',
|
||
});
|
||
};
|
||
|
||
export const logout = () => {
|
||
return request({
|
||
url: '/auth/token/logout',
|
||
method: 'delete',
|
||
});
|
||
};
|