添加二次认证
This commit is contained in:
parent
160fcb7c9c
commit
10d6cce1bf
|
|
@ -50,6 +50,7 @@
|
|||
"vue-cropper": "1.1.1",
|
||||
"vue-cropperjs": "^5.0.0",
|
||||
"vue-echarts": "^6.6.9",
|
||||
"vue-qr": "^4.0.9",
|
||||
"vue-router": "^4.2.5",
|
||||
"vue-schart": "^2.0.0",
|
||||
"xlsx": "^0.18.5"
|
||||
|
|
@ -2564,6 +2565,20 @@
|
|||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/decompress-response": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
|
||||
"integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
|
||||
"dependencies": {
|
||||
"mimic-response": "^3.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/deepmerge": {
|
||||
"version": "1.5.2",
|
||||
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-1.5.2.tgz",
|
||||
|
|
@ -3355,6 +3370,11 @@
|
|||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/fs.realpath": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||
|
|
@ -3528,6 +3548,21 @@
|
|||
"url": "https://opencollective.com/immer"
|
||||
}
|
||||
},
|
||||
"node_modules/inflight": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
||||
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
|
||||
"deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.",
|
||||
"dependencies": {
|
||||
"once": "^1.3.0",
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/inherits": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
||||
},
|
||||
"node_modules/ini": {
|
||||
"version": "1.3.8",
|
||||
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
|
||||
|
|
@ -3665,6 +3700,11 @@
|
|||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/js-binary-schema-parser": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/js-binary-schema-parser/-/js-binary-schema-parser-2.0.3.tgz",
|
||||
"integrity": "sha512-xezGJmOb4lk/M1ZZLTR/jaBHQ4gG/lqQnJqdIv4721DMggsa1bDVlHXNeHYogaIEHD9vCRv0fcL4hMA+Coarkg=="
|
||||
},
|
||||
"node_modules/js-cookie": {
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz",
|
||||
|
|
@ -4598,11 +4638,21 @@
|
|||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/mimic-response": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
|
||||
"integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "5.1.6",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
|
||||
"integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
},
|
||||
|
|
@ -4740,6 +4790,14 @@
|
|||
"resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz",
|
||||
"integrity": "sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA=="
|
||||
},
|
||||
"node_modules/once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
||||
"dependencies": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/package-json-from-dist": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
|
||||
|
|
@ -4761,6 +4819,11 @@
|
|||
"path-to-regexp": "~1.2.1"
|
||||
}
|
||||
},
|
||||
"node_modules/parenthesis": {
|
||||
"version": "3.1.8",
|
||||
"resolved": "https://registry.npmjs.org/parenthesis/-/parenthesis-3.1.8.tgz",
|
||||
"integrity": "sha512-KF/U8tk54BgQewkJPvB4s/US3VQY68BRDpH638+7O/n58TpnwiwnOtGIOsT2/i+M78s61BBpeC83STB88d8sqw=="
|
||||
},
|
||||
"node_modules/path-data-parser": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/path-data-parser/-/path-data-parser-0.1.0.tgz",
|
||||
|
|
@ -5207,6 +5270,49 @@
|
|||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/simple-concat": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz",
|
||||
"integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/simple-get": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz",
|
||||
"integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"decompress-response": "^6.0.0",
|
||||
"once": "^1.3.1",
|
||||
"simple-concat": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/slate": {
|
||||
"version": "0.72.8",
|
||||
"resolved": "https://registry.npmjs.org/slate/-/slate-0.72.8.tgz",
|
||||
|
|
@ -5284,6 +5390,14 @@
|
|||
"resolved": "https://registry.npmjs.org/ssr-window/-/ssr-window-3.0.0.tgz",
|
||||
"integrity": "sha512-q+8UfWDg9Itrg0yWK7oe5p/XRCJpJF9OBtXfOPgSJl+u3Xd5KI328RUEvUqSMVM9CiQUEf1QdBzJMkYGErj9QA=="
|
||||
},
|
||||
"node_modules/string-split-by": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/string-split-by/-/string-split-by-1.0.0.tgz",
|
||||
"integrity": "sha512-KaJKY+hfpzNyet/emP81PJA9hTVSfxNLS9SFTWxdCnnW1/zOOwiV248+EfoX7IQFcBaOp4G5YE6xTJMF+pLg6A==",
|
||||
"dependencies": {
|
||||
"parenthesis": "^3.1.5"
|
||||
}
|
||||
},
|
||||
"node_modules/string-width": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
|
||||
|
|
@ -5912,6 +6026,36 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/vue-qr": {
|
||||
"version": "4.0.9",
|
||||
"resolved": "https://registry.npmjs.org/vue-qr/-/vue-qr-4.0.9.tgz",
|
||||
"integrity": "sha512-pAISV94T0MNEYA3NGjykUpsXRE2QfaNxlu9ZhEL6CERgqNc21hJYuP3hRVzAWfBQlgO18DPmZTbrFerJC3+Ikw==",
|
||||
"dependencies": {
|
||||
"glob": "^8.0.1",
|
||||
"js-binary-schema-parser": "^2.0.2",
|
||||
"simple-get": "^4.0.1",
|
||||
"string-split-by": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vue-qr/node_modules/glob": {
|
||||
"version": "8.1.0",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz",
|
||||
"integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==",
|
||||
"deprecated": "Glob versions prior to v9 are no longer supported",
|
||||
"dependencies": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
"inflight": "^1.0.4",
|
||||
"inherits": "2",
|
||||
"minimatch": "^5.0.1",
|
||||
"once": "^1.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/vue-route": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/vue-route/-/vue-route-1.5.1.tgz",
|
||||
|
|
@ -6101,6 +6245,11 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
|
||||
},
|
||||
"node_modules/xlsx": {
|
||||
"version": "0.18.5",
|
||||
"resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.18.5.tgz",
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@
|
|||
"vue-cropper": "1.1.1",
|
||||
"vue-cropperjs": "^5.0.0",
|
||||
"vue-echarts": "^6.6.9",
|
||||
"vue-qr": "^4.0.9",
|
||||
"vue-router": "^4.2.5",
|
||||
"vue-schart": "^2.0.0",
|
||||
"xlsx": "^0.18.5"
|
||||
|
|
|
|||
|
|
@ -245,7 +245,7 @@ export const getGithubLoginUrl = (Data) => {
|
|||
|
||||
//获取第三方登录状态
|
||||
export const getThirdPartyLoginStatus = (Data) => {
|
||||
let url ='/user/oAuth' + "?uuid=" + Data.uuid
|
||||
let url ='/user/oAuth' + "?uuid=" + Data.uuid + "&host_id=" + Data.host_id
|
||||
return request.get(url)
|
||||
}
|
||||
|
||||
|
|
@ -285,7 +285,41 @@ export const getTokenByCode = (Data) => {
|
|||
})
|
||||
}
|
||||
|
||||
//生成totp密钥
|
||||
export const genTOTPSecret = (Data) => {
|
||||
return request.get('/tool/gen_totp_secret', {
|
||||
headers: {
|
||||
'token': Data.token,
|
||||
}
|
||||
})
|
||||
}
|
||||
export const getTOTPSecretInfo = (Data) => {
|
||||
return request.get('/tool/get_totp_secret_info', {
|
||||
headers: {
|
||||
'token': Data.token,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const unBindTOTPSecretService = (Data) => {
|
||||
return request.delete('/tool/del_totp_secret', {
|
||||
headers: {
|
||||
'token': Data.token,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const secondAuthLoginService = (Data) => {
|
||||
let token = Data.token
|
||||
delete Data.token
|
||||
return request.post('/user/second_auth' , Data, {
|
||||
headers: {
|
||||
'token': token,
|
||||
'Content-Type': 'application/json' // 设置请求头为 JSON 格式
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
export const fetchUserData = () => {
|
||||
return {
|
||||
"list": [
|
||||
|
|
|
|||
|
|
@ -109,6 +109,35 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-dialog
|
||||
v-model="second_auth_visible"
|
||||
title="二次认证"
|
||||
:close-on-click-modal="false"
|
||||
width="30%"
|
||||
>
|
||||
<!-- 输入验证码 -->
|
||||
<span>请选择二次认证方式</span>
|
||||
<el-select v-model="second_auth_method" placeholder="请选择认证方式" style="width: 100%; margin-top: 20px;">
|
||||
<el-option v-for="item in second_auth_type_list" :key="item" :label="item.toUpperCase()" :value="item"></el-option>
|
||||
</el-select>
|
||||
<el-row>
|
||||
<span>输入验证码</span>
|
||||
<el-input placeholder="请输入验证码" style="width: 100%; margin-top: 20px;" v-model="second_auth_code" >
|
||||
<template #prepend>
|
||||
<el-icon>
|
||||
<Lock />
|
||||
</el-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-row>
|
||||
|
||||
<el-row>
|
||||
<el-button class="login-btn"
|
||||
type="primary"
|
||||
size="large" @click="secondAuthLogin">确认</el-button>
|
||||
</el-row>
|
||||
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
@ -122,7 +151,7 @@ import { UserToken } from "@/types/user";
|
|||
import { getBrowserFingerprint,getStoredFingerprint } from "@/utils/fingerprint";
|
||||
import { usePermissStore } from "@/store/permiss";
|
||||
import Cookies from 'js-cookie';
|
||||
import {getThirdPartyUUID,getThirdPartyLoginStatus,getThirdPartyLoginUrl,sendLoginCode, loginByCode} from "@/api/user";
|
||||
import {getThirdPartyUUID,getThirdPartyLoginStatus,getThirdPartyLoginUrl,sendLoginCode, loginByCode, secondAuthLoginService} from "@/api/user";
|
||||
import { log, time } from "console";
|
||||
import { pa } from "element-plus/es/locale";
|
||||
// 从本地存储获取登录参数
|
||||
|
|
@ -137,6 +166,7 @@ const countdown = ref(0); //倒计时
|
|||
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
const second_auth_visible = ref(false); //二次认证弹窗
|
||||
// 登录表单数据
|
||||
const param = reactive({
|
||||
username: defParam ? defParam.username : "",
|
||||
|
|
@ -175,6 +205,38 @@ const maxLoginRepeatRequest = 60; //最大请求次数
|
|||
const currentLoginRequest = ref(0); //当前请求次数
|
||||
const timer = ref(null); //定时器
|
||||
|
||||
const secondAuthLogin = async () => {
|
||||
if(!second_auth_method.value){
|
||||
ElMessage.error("请选择认证方式");
|
||||
return;
|
||||
}
|
||||
if(!second_auth_code.value){
|
||||
ElMessage.error("请输入验证码");
|
||||
return;
|
||||
}
|
||||
let req = {
|
||||
state: second_auth_state_key.value,
|
||||
type: second_auth_method.value,
|
||||
code: second_auth_code.value
|
||||
};
|
||||
let result = await secondAuthLoginService(req);
|
||||
if (result["code"] === 0) {
|
||||
ElMessage.success("登录成功");
|
||||
let userTokenInfo: UserToken = result["data"];
|
||||
globalData["token"] = result.data;
|
||||
localStorage.setItem("token", userTokenInfo.access_token);
|
||||
localStorage.setItem("refresh_token", userTokenInfo.refresh_token);
|
||||
localStorage.setItem("userId", userTokenInfo.user_id.toString());
|
||||
localStorage.setItem("username", userTokenInfo.username);
|
||||
let now = new Date();
|
||||
localStorage.setItem("end_time", (now.setDate(now.getHours())).toString()); //过期时间
|
||||
await getMyUserInfo(userTokenInfo.user_id);
|
||||
}else{
|
||||
ElMessage.error(result["message"] || "登录失败!请稍后再试");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
const thirdPartyLogoInfoList = ref([
|
||||
{
|
||||
name: "github",
|
||||
|
|
@ -234,6 +296,10 @@ var loginData = ref({
|
|||
fingerprint: '' // 浏览器指纹
|
||||
});
|
||||
const querySite =ref("");
|
||||
const second_auth_state_key = ref(""); //二次认证状态key
|
||||
const second_auth_method = ref("");
|
||||
const second_auth_type_list = ref([]);
|
||||
const second_auth_code = ref(""); //二次认证验证码
|
||||
|
||||
onMounted(async () => {
|
||||
let fp = await getStoredFingerprint();
|
||||
|
|
@ -291,7 +357,7 @@ const thirdLogin = async (type) => {
|
|||
ElMessage.error("登录超时,请重新登录!");
|
||||
return;
|
||||
}
|
||||
let statusResp = await getThirdPartyLoginStatus({uuid: uuid});
|
||||
let statusResp = await getThirdPartyLoginStatus({uuid: uuid,host_id:loginData.value.fingerprint});
|
||||
if (statusResp["code"] !== 0) {
|
||||
ElMessage.error("获取登录状态失败!请稍后再试");
|
||||
clearInterval(timer.value);
|
||||
|
|
@ -408,6 +474,18 @@ const onLogin = async () => {
|
|||
console.log("login result:", result);
|
||||
if (result["code"] === 0) {
|
||||
ElMessage.success("登录成功");
|
||||
}else if (result["code"] == 1102) {
|
||||
//需二次认证,支持方式
|
||||
second_auth_visible.value = true;
|
||||
second_auth_state_key.value = result["data"]["state"];
|
||||
let types = result["data"]["type"];
|
||||
second_auth_type_list.value = types.split(",");
|
||||
//删除''空值
|
||||
second_auth_type_list.value = second_auth_type_list.value.filter(item => item);
|
||||
second_auth_method.value = second_auth_type_list.value[0];
|
||||
console.log("second_auth_type_list:", second_auth_type_list.value);
|
||||
return;
|
||||
|
||||
}else if(result["code"] === 1101){
|
||||
ElMessage.error(result["message"] || "该账号已被禁用,请联系管理员!");
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -109,6 +109,28 @@
|
|||
</template>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane name="label6" label="二次认证" class="user-tabpane">
|
||||
<div>
|
||||
<p>TOTP密钥</p>
|
||||
<el-button type="primary" @click="GenTOTPSecret" :disabled="gen_totp_secret">生成TOTP密钥</el-button>
|
||||
<div v-if="totp_secret || totp_url" style="margin-top: 20px;">
|
||||
<!-- 提示 -->
|
||||
<p>使用支持TOTP的应用(如Google Authenticator、Authy等)扫描二维码或手动输入密钥进行绑定。</p>
|
||||
<p>请妥善保存您的TOTP密钥,只能查看一次,若丢失请解绑后重新生成。</p>
|
||||
<el-button type="primary" @click="onCopyTOTPSecret" v-if="totp_secret">点击复制密钥</el-button>
|
||||
<vueQr v-if="totp_url" :text="totp_url" :size="200" :margin="20" :background="'#ffffff'" :foreground="'#000000'" />
|
||||
</div>
|
||||
<el-row :gutter="20" class="user-tabpane">
|
||||
<el-col :span="12" v-if="totp_secret_created_at">
|
||||
<el-tag>密钥创建时间:{{ totp_secret_created_at }}</el-tag>
|
||||
</el-col>
|
||||
<el-col :span="12" v-if="totp_secret_created_at">
|
||||
<el-button type="danger" @click="unBindTOTPSecret">解绑</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-card>
|
||||
</div>
|
||||
|
|
@ -121,7 +143,7 @@ import { VueCropper } from 'vue-cropper';
|
|||
import 'vue-cropper/dist/index.css';
|
||||
import avatar from '@/assets/img/img.jpg';
|
||||
import TabsComp from '../element/tabs.vue';
|
||||
import {GetUserInfoService} from "@/api/user";
|
||||
import {GetUserInfoService, genTOTPSecret, unBindTOTPSecretService, getTOTPSecretInfo} from "@/api/user";
|
||||
import { GetUserStatisticService } from "@/api/user";
|
||||
import { UploadFileService } from "@/api/tool";
|
||||
import { UserInfo } from '@/types/user';
|
||||
|
|
@ -133,6 +155,7 @@ import {genResetPassword} from "@/api/user";
|
|||
import {updateUserInfoService} from "@/api/user";
|
||||
import { useRouter } from "vue-router";
|
||||
import {getThirdPartyUUID,getThirdPartyLoginStatus,getThirdPartyLoginUrl, getThirdPartyInfo, deleteThirdPartyInfo} from "@/api/user";
|
||||
import vueQr from 'vue-qr/src/packages/vue-qr.vue'
|
||||
|
||||
const name = localStorage.getItem('ms_username');
|
||||
const qqButtonBgImage = ref('https://wiki.connect.qq.com/wp-content/uploads/2016/12/Connect_logo_4.png');
|
||||
|
|
@ -147,6 +170,7 @@ const userStatistic = reactive({
|
|||
total: 0,
|
||||
file_count: 0,
|
||||
});
|
||||
const gen_totp_secret = ref(false);
|
||||
const userInfo = ref<UserInfo>();
|
||||
const isUserInfoLoaded = ref(false);
|
||||
const globalData = inject("globalData");
|
||||
|
|
@ -160,6 +184,9 @@ const cropImg = ref('');
|
|||
const cropper: any = ref();
|
||||
const maxLoginRepeatRequest = 60; //最大请求次数
|
||||
const currentLoginRequest = ref(0); //当前请求次数
|
||||
const totp_secret = ref('');
|
||||
const totp_url = ref('');
|
||||
const totp_secret_created_at = ref('');
|
||||
|
||||
const thirdPartyUserInfo = ref<ThirdPartyUserInfo[]>([]);
|
||||
|
||||
|
|
@ -174,7 +201,74 @@ const thirdPartyPlatform = ref([
|
|||
{ label: "Gitea自建", value: "my_gitea"},
|
||||
{ label: "Microsoft", value: "microsoft"}
|
||||
]);
|
||||
const onCopyTOTPSecret = () => {
|
||||
navigator.clipboard.writeText(totp_secret.value).then(() => {
|
||||
ElMessage.success('复制成功!');
|
||||
}).catch(() => {
|
||||
ElMessage.error('复制失败,请手动复制');
|
||||
});
|
||||
};
|
||||
|
||||
const unBindTOTPSecret =async () => {
|
||||
let req = {
|
||||
token: localStorage.getItem('token'),
|
||||
};
|
||||
try{
|
||||
let result = await unBindTOTPSecretService(req);
|
||||
if (result["code"] == 0) {
|
||||
ElMessage.success("解绑成功");
|
||||
totp_secret.value = '';
|
||||
totp_url.value = '';
|
||||
totp_secret_created_at.value = '';
|
||||
gen_totp_secret.value = false;
|
||||
}else{
|
||||
ElMessage.error(result["msg"]);
|
||||
}
|
||||
}catch(e){
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
|
||||
const GenTOTPSecret = async () => {
|
||||
let req = {
|
||||
token: localStorage.getItem('token'),
|
||||
};
|
||||
try{
|
||||
let result = await genTOTPSecret(req);
|
||||
if (result["code"] == 0) {
|
||||
totp_secret.value = result["data"]["secret"];
|
||||
totp_url.value = result["data"]["url"];
|
||||
gen_totp_secret.value = true;
|
||||
ElMessage.success("TOTP密钥生成成功,请妥善保存,建议使用Google Authenticator等支持TOTP的应用扫码保存,只能查询一次");
|
||||
//生成显示二维码
|
||||
}else{
|
||||
ElMessage.error(result["msg"]);
|
||||
}
|
||||
}catch(e){
|
||||
console.log(e);
|
||||
}
|
||||
};
|
||||
|
||||
const GetTOTPSecret = async () => {
|
||||
let req = {
|
||||
token: localStorage.getItem('token'),
|
||||
};
|
||||
try{
|
||||
let result = await getTOTPSecretInfo(req);
|
||||
if (result["code"] == 0) {
|
||||
if (result["data"]["ID"] != 0) {
|
||||
totp_secret_created_at.value = result["data"]["CreatedAt"];
|
||||
gen_totp_secret.value = true;
|
||||
}
|
||||
}else{
|
||||
ElMessage.error(result["msg"]);
|
||||
}
|
||||
}catch(e){
|
||||
console.log(e);
|
||||
}
|
||||
};
|
||||
|
||||
GetTOTPSecret();
|
||||
|
||||
const reset_password = () => {
|
||||
localStorage.removeItem("ms_username");
|
||||
|
|
|
|||
96
yarn.lock
96
yarn.lock
|
|
@ -1821,6 +1821,13 @@ decode-named-character-reference@^1.0.0:
|
|||
dependencies:
|
||||
character-entities "^2.0.0"
|
||||
|
||||
decompress-response@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz"
|
||||
integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==
|
||||
dependencies:
|
||||
mimic-response "^3.1.0"
|
||||
|
||||
deepmerge@^1.2.0:
|
||||
version "1.5.2"
|
||||
resolved "https://registry.npmjs.org/deepmerge/-/deepmerge-1.5.2.tgz"
|
||||
|
|
@ -2143,6 +2150,11 @@ frac@~1.1.2:
|
|||
resolved "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz"
|
||||
integrity sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==
|
||||
|
||||
fs.realpath@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz"
|
||||
integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
|
||||
|
||||
function-bind@^1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz"
|
||||
|
|
@ -2167,6 +2179,17 @@ glob@^10.4.2:
|
|||
package-json-from-dist "^1.0.0"
|
||||
path-scurry "^1.11.1"
|
||||
|
||||
glob@^8.0.1:
|
||||
version "8.1.0"
|
||||
resolved "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz"
|
||||
integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==
|
||||
dependencies:
|
||||
fs.realpath "^1.0.0"
|
||||
inflight "^1.0.4"
|
||||
inherits "2"
|
||||
minimatch "^5.0.1"
|
||||
once "^1.3.0"
|
||||
|
||||
globals@^15.14.0:
|
||||
version "15.15.0"
|
||||
resolved "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz"
|
||||
|
|
@ -2239,6 +2262,19 @@ immer@^9.0.6:
|
|||
resolved "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz"
|
||||
integrity sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==
|
||||
|
||||
inflight@^1.0.4:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz"
|
||||
integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==
|
||||
dependencies:
|
||||
once "^1.3.0"
|
||||
wrappy "1"
|
||||
|
||||
inherits@2:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz"
|
||||
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
|
||||
|
||||
ini@^1.3.4:
|
||||
version "1.3.8"
|
||||
resolved "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz"
|
||||
|
|
@ -2335,6 +2371,11 @@ js-beautify@^1.14.9:
|
|||
js-cookie "^3.0.5"
|
||||
nopt "^7.2.1"
|
||||
|
||||
js-binary-schema-parser@^2.0.2:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.npmjs.org/js-binary-schema-parser/-/js-binary-schema-parser-2.0.3.tgz"
|
||||
integrity sha512-xezGJmOb4lk/M1ZZLTR/jaBHQ4gG/lqQnJqdIv4721DMggsa1bDVlHXNeHYogaIEHD9vCRv0fcL4hMA+Coarkg==
|
||||
|
||||
js-cookie@^3.0.5:
|
||||
version "3.0.5"
|
||||
resolved "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz"
|
||||
|
|
@ -2960,7 +3001,12 @@ mime-types@^2.1.12:
|
|||
dependencies:
|
||||
mime-db "1.52.0"
|
||||
|
||||
minimatch@^5.1.1:
|
||||
mimic-response@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz"
|
||||
integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==
|
||||
|
||||
minimatch@^5.0.1, minimatch@^5.1.1:
|
||||
version "5.1.6"
|
||||
resolved "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz"
|
||||
integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==
|
||||
|
|
@ -3058,6 +3104,13 @@ nprogress@^0.2.0:
|
|||
resolved "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz"
|
||||
integrity sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==
|
||||
|
||||
once@^1.3.0, once@^1.3.1:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz"
|
||||
integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==
|
||||
dependencies:
|
||||
wrappy "1"
|
||||
|
||||
package-json-from-dist@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz"
|
||||
|
|
@ -3077,6 +3130,11 @@ page@^1.5.0:
|
|||
dependencies:
|
||||
path-to-regexp "~1.2.1"
|
||||
|
||||
parenthesis@^3.1.5:
|
||||
version "3.1.8"
|
||||
resolved "https://registry.npmjs.org/parenthesis/-/parenthesis-3.1.8.tgz"
|
||||
integrity sha512-KF/U8tk54BgQewkJPvB4s/US3VQY68BRDpH638+7O/n58TpnwiwnOtGIOsT2/i+M78s61BBpeC83STB88d8sqw==
|
||||
|
||||
path-data-parser@^0.1.0, path-data-parser@0.1.0:
|
||||
version "0.1.0"
|
||||
resolved "https://registry.npmjs.org/path-data-parser/-/path-data-parser-0.1.0.tgz"
|
||||
|
|
@ -3360,6 +3418,20 @@ signal-exit@^4.0.1:
|
|||
resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz"
|
||||
integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==
|
||||
|
||||
simple-concat@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz"
|
||||
integrity sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==
|
||||
|
||||
simple-get@^4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz"
|
||||
integrity sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==
|
||||
dependencies:
|
||||
decompress-response "^6.0.0"
|
||||
once "^1.3.1"
|
||||
simple-concat "^1.0.0"
|
||||
|
||||
slate-history@^0.66.0:
|
||||
version "0.66.0"
|
||||
resolved "https://registry.npmjs.org/slate-history/-/slate-history-0.66.0.tgz"
|
||||
|
|
@ -3416,6 +3488,13 @@ ssr-window@^3.0.0-alpha.1:
|
|||
resolved "https://registry.npmjs.org/ssr-window/-/ssr-window-3.0.0.tgz"
|
||||
integrity sha512-q+8UfWDg9Itrg0yWK7oe5p/XRCJpJF9OBtXfOPgSJl+u3Xd5KI328RUEvUqSMVM9CiQUEf1QdBzJMkYGErj9QA==
|
||||
|
||||
string-split-by@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.npmjs.org/string-split-by/-/string-split-by-1.0.0.tgz"
|
||||
integrity sha512-KaJKY+hfpzNyet/emP81PJA9hTVSfxNLS9SFTWxdCnnW1/zOOwiV248+EfoX7IQFcBaOp4G5YE6xTJMF+pLg6A==
|
||||
dependencies:
|
||||
parenthesis "^3.1.5"
|
||||
|
||||
"string-width-cjs@npm:string-width@^4.2.0":
|
||||
version "4.2.3"
|
||||
resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz"
|
||||
|
|
@ -3762,6 +3841,16 @@ vue-echarts@^6.6.9:
|
|||
resize-detector "^0.3.0"
|
||||
vue-demi "^0.13.11"
|
||||
|
||||
vue-qr@^4.0.9:
|
||||
version "4.0.9"
|
||||
resolved "https://registry.npmjs.org/vue-qr/-/vue-qr-4.0.9.tgz"
|
||||
integrity sha512-pAISV94T0MNEYA3NGjykUpsXRE2QfaNxlu9ZhEL6CERgqNc21hJYuP3hRVzAWfBQlgO18DPmZTbrFerJC3+Ikw==
|
||||
dependencies:
|
||||
glob "^8.0.1"
|
||||
js-binary-schema-parser "^2.0.2"
|
||||
simple-get "^4.0.1"
|
||||
string-split-by "^1.0.0"
|
||||
|
||||
vue-route@^1.5.1:
|
||||
version "1.5.1"
|
||||
resolved "https://registry.npmjs.org/vue-route/-/vue-route-1.5.1.tgz"
|
||||
|
|
@ -3874,6 +3963,11 @@ wrap-ansi@^8.1.0:
|
|||
string-width "^5.0.1"
|
||||
strip-ansi "^7.0.1"
|
||||
|
||||
wrappy@1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz"
|
||||
integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
|
||||
|
||||
xlsx@^0.18.5:
|
||||
version "0.18.5"
|
||||
resolved "https://registry.npmjs.org/xlsx/-/xlsx-0.18.5.tgz"
|
||||
|
|
|
|||
Loading…
Reference in New Issue