mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-22 07:03:53 +08:00
Merge branch 'sm2_test' of https://github.com/xinnan-tech/xiaozhi-esp32-server into sm2_test
This commit is contained in:
@@ -68,6 +68,7 @@ export interface PublicConfig {
|
|||||||
beianIcpNum: string
|
beianIcpNum: string
|
||||||
beianGaNum: string
|
beianGaNum: string
|
||||||
name: string
|
name: string
|
||||||
|
sm2PublicKey: string
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取用户信息
|
// 获取用户信息
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import type { PublicConfig } from '@/api/auth'
|
import type { PublicConfig } from '@/api/auth'
|
||||||
|
import { getPublicConfig } from '@/api/auth'
|
||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { getPublicConfig } from '@/api/auth'
|
|
||||||
|
|
||||||
// 初始化状态
|
// 初始化状态
|
||||||
const initialConfigState: PublicConfig = {
|
const initialConfigState: PublicConfig = {
|
||||||
@@ -12,6 +12,7 @@ const initialConfigState: PublicConfig = {
|
|||||||
mobileAreaList: [],
|
mobileAreaList: [],
|
||||||
beianIcpNum: '',
|
beianIcpNum: '',
|
||||||
beianGaNum: '',
|
beianGaNum: '',
|
||||||
|
sm2PublicKey: '',
|
||||||
name: import.meta.env.VITE_APP_TITLE,
|
name: import.meta.env.VITE_APP_TITLE,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Generated
+43
-5
@@ -10,13 +10,16 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"core-js": "^3.41.0",
|
"core-js": "^3.41.0",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
|
"dotenv": "^16.5.0",
|
||||||
"element-ui": "^2.15.14",
|
"element-ui": "^2.15.14",
|
||||||
"flyio": "^0.6.14",
|
"flyio": "^0.6.14",
|
||||||
"normalize.css": "^8.0.1",
|
"normalize.css": "^8.0.1",
|
||||||
"opus-decoder": "^0.7.7",
|
"opus-decoder": "^0.7.7",
|
||||||
"opus-recorder": "^8.0.5",
|
"opus-recorder": "^8.0.5",
|
||||||
|
"sm-crypto": "^0.3.13",
|
||||||
"vue": "^2.6.14",
|
"vue": "^2.6.14",
|
||||||
"vue-axios": "^3.5.2",
|
"vue-axios": "^3.5.2",
|
||||||
|
"vue-i18n": "^8.28.2",
|
||||||
"vue-router": "^3.6.5",
|
"vue-router": "^3.6.5",
|
||||||
"vuex": "^3.6.2",
|
"vuex": "^3.6.2",
|
||||||
"xiaozhi": "file:"
|
"xiaozhi": "file:"
|
||||||
@@ -2540,6 +2543,16 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@vue/cli-service/node_modules/dotenv": {
|
||||||
|
"version": "10.0.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/dotenv/-/dotenv-10.0.0.tgz",
|
||||||
|
"integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "BSD-2-Clause",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@vue/cli-shared-utils": {
|
"node_modules/@vue/cli-shared-utils": {
|
||||||
"version": "5.0.8",
|
"version": "5.0.8",
|
||||||
"resolved": "https://registry.npmmirror.com/@vue/cli-shared-utils/-/cli-shared-utils-5.0.8.tgz",
|
"resolved": "https://registry.npmmirror.com/@vue/cli-shared-utils/-/cli-shared-utils-5.0.8.tgz",
|
||||||
@@ -4776,12 +4789,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/dotenv": {
|
"node_modules/dotenv": {
|
||||||
"version": "10.0.0",
|
"version": "16.6.1",
|
||||||
"resolved": "https://registry.npmmirror.com/dotenv/-/dotenv-10.0.0.tgz",
|
"resolved": "https://registry.npmmirror.com/dotenv/-/dotenv-16.6.1.tgz",
|
||||||
"integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==",
|
"integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==",
|
||||||
"dev": true,
|
"license": "BSD-2-Clause",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10"
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://dotenvx.com"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/dotenv-expand": {
|
"node_modules/dotenv-expand": {
|
||||||
@@ -10114,6 +10130,21 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/sm-crypto": {
|
||||||
|
"version": "0.3.13",
|
||||||
|
"resolved": "https://registry.npmmirror.com/sm-crypto/-/sm-crypto-0.3.13.tgz",
|
||||||
|
"integrity": "sha512-ztNF+pZq6viCPMA1A6KKu3bgpkmYti5avykRHbcFIdSipFdkVmfUw2CnpM2kBJyppIalqvczLNM3wR8OQ0pT5w==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"jsbn": "^1.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/sm-crypto/node_modules/jsbn": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/jsbn/-/jsbn-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/smob": {
|
"node_modules/smob": {
|
||||||
"version": "1.5.0",
|
"version": "1.5.0",
|
||||||
"resolved": "https://registry.npmmirror.com/smob/-/smob-1.5.0.tgz",
|
"resolved": "https://registry.npmmirror.com/smob/-/smob-1.5.0.tgz",
|
||||||
@@ -11131,6 +11162,13 @@
|
|||||||
"integrity": "sha512-BXq3jwIagosjgNVae6tkHzzIk6a8MHFtzAdwhnV5VlvPTFxDCvIttgSiHWjdGoTJvXtmRu5HacExfdarRcFhog==",
|
"integrity": "sha512-BXq3jwIagosjgNVae6tkHzzIk6a8MHFtzAdwhnV5VlvPTFxDCvIttgSiHWjdGoTJvXtmRu5HacExfdarRcFhog==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/vue-i18n": {
|
||||||
|
"version": "8.28.2",
|
||||||
|
"resolved": "https://registry.npmmirror.com/vue-i18n/-/vue-i18n-8.28.2.tgz",
|
||||||
|
"integrity": "sha512-C5GZjs1tYlAqjwymaaCPDjCyGo10ajUphiwA922jKt9n7KPpqR7oM1PCwYzhB/E7+nT3wfdG3oRre5raIT1rKA==",
|
||||||
|
"deprecated": "Vue I18n v8.x has reached EOL and is no longer actively maintained. About maintenance status, see https://vue-i18n.intlify.dev/guide/maintenance.html",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/vue-loader": {
|
"node_modules/vue-loader": {
|
||||||
"version": "17.4.2",
|
"version": "17.4.2",
|
||||||
"resolved": "https://registry.npmmirror.com/vue-loader/-/vue-loader-17.4.2.tgz",
|
"resolved": "https://registry.npmmirror.com/vue-loader/-/vue-loader-17.4.2.tgz",
|
||||||
|
|||||||
@@ -1050,7 +1050,6 @@ export default {
|
|||||||
'info': 'Info',
|
'info': 'Info',
|
||||||
'common.networkError': 'Network request failed',
|
'common.networkError': 'Network request failed',
|
||||||
'sm2.publicKeyNotConfigured': 'SM2 public key not configured, please contact administrator',
|
'sm2.publicKeyNotConfigured': 'SM2 public key not configured, please contact administrator',
|
||||||
'sm2.failedToGetPublicKey': 'Failed to get SM2 public key',
|
|
||||||
'sm2.encryptionFailed': 'Password encryption failed',
|
'sm2.encryptionFailed': 'Password encryption failed',
|
||||||
'sm2.keyGenerationFailed': 'Key pair generation failed',
|
'sm2.keyGenerationFailed': 'Key pair generation failed',
|
||||||
'sm2.invalidPublicKey': 'Invalid public key format',
|
'sm2.invalidPublicKey': 'Invalid public key format',
|
||||||
|
|||||||
@@ -1051,7 +1051,6 @@ export default {
|
|||||||
'common.networkError': '网络请求失败',
|
'common.networkError': '网络请求失败',
|
||||||
// SM2加密相关错误消息
|
// SM2加密相关错误消息
|
||||||
'sm2.publicKeyNotConfigured': 'SM2公钥未配置,请联系管理员',
|
'sm2.publicKeyNotConfigured': 'SM2公钥未配置,请联系管理员',
|
||||||
'sm2.failedToGetPublicKey': '获取SM2公钥失败',
|
|
||||||
'sm2.encryptionFailed': '密码加密失败',
|
'sm2.encryptionFailed': '密码加密失败',
|
||||||
'sm2.keyGenerationFailed': '密钥对生成失败',
|
'sm2.keyGenerationFailed': '密钥对生成失败',
|
||||||
'sm2.invalidPublicKey': '无效的公钥格式',
|
'sm2.invalidPublicKey': '无效的公钥格式',
|
||||||
|
|||||||
@@ -1052,7 +1052,6 @@ export default {
|
|||||||
|
|
||||||
// SM2加密相關錯誤消息
|
// SM2加密相關錯誤消息
|
||||||
'sm2.publicKeyNotConfigured': 'SM2公鑰未配置,請聯繫管理員',
|
'sm2.publicKeyNotConfigured': 'SM2公鑰未配置,請聯繫管理員',
|
||||||
'sm2.failedToGetPublicKey': '獲取SM2公鑰失敗',
|
|
||||||
'sm2.encryptionFailed': '密碼加密失敗',
|
'sm2.encryptionFailed': '密碼加密失敗',
|
||||||
'sm2.keyGenerationFailed': '金鑰對生成失敗',
|
'sm2.keyGenerationFailed': '金鑰對生成失敗',
|
||||||
'sm2.invalidPublicKey': '無效的公鑰格式',
|
'sm2.invalidPublicKey': '無效的公鑰格式',
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ export default new Vuex.Store({
|
|||||||
version: '',
|
version: '',
|
||||||
beianIcpNum: 'null',
|
beianIcpNum: 'null',
|
||||||
beianGaNum: 'null',
|
beianGaNum: 'null',
|
||||||
allowUserRegister: false
|
allowUserRegister: false,
|
||||||
|
sm2PublicKey: ''
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getters: {
|
getters: {
|
||||||
|
|||||||
@@ -148,9 +148,8 @@
|
|||||||
import Api from "@/apis/api";
|
import Api from "@/apis/api";
|
||||||
import VersionFooter from "@/components/VersionFooter.vue";
|
import VersionFooter from "@/components/VersionFooter.vue";
|
||||||
import i18n, { changeLanguage } from "@/i18n";
|
import i18n, { changeLanguage } from "@/i18n";
|
||||||
import { getUUID, goToPage, showDanger, showSuccess, validateMobile, sm2Encrypt } from "@/utils";
|
import { getUUID, goToPage, showDanger, showSuccess, sm2Encrypt, validateMobile } from "@/utils";
|
||||||
import { mapState } from "vuex";
|
import { mapState } from "vuex";
|
||||||
import Constant from "@/utils/constant";
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "login",
|
name: "login",
|
||||||
@@ -162,6 +161,7 @@ export default {
|
|||||||
allowUserRegister: (state) => state.pubConfig.allowUserRegister,
|
allowUserRegister: (state) => state.pubConfig.allowUserRegister,
|
||||||
enableMobileRegister: (state) => state.pubConfig.enableMobileRegister,
|
enableMobileRegister: (state) => state.pubConfig.enableMobileRegister,
|
||||||
mobileAreaList: (state) => state.pubConfig.mobileAreaList,
|
mobileAreaList: (state) => state.pubConfig.mobileAreaList,
|
||||||
|
sm2PublicKey: (state) => state.pubConfig.sm2PublicKey,
|
||||||
}),
|
}),
|
||||||
// 获取当前语言
|
// 获取当前语言
|
||||||
currentLanguage() {
|
currentLanguage() {
|
||||||
@@ -197,7 +197,6 @@ export default {
|
|||||||
captchaUrl: "",
|
captchaUrl: "",
|
||||||
isMobileLogin: false,
|
isMobileLogin: false,
|
||||||
languageDropdownVisible: false,
|
languageDropdownVisible: false,
|
||||||
serverPublicKey: "", // 服务器公钥
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
@@ -206,38 +205,8 @@ export default {
|
|||||||
// 根据配置决定默认登录方式
|
// 根据配置决定默认登录方式
|
||||||
this.isMobileLogin = this.enableMobileRegister;
|
this.isMobileLogin = this.enableMobileRegister;
|
||||||
});
|
});
|
||||||
// 获取服务器公钥
|
|
||||||
this.getServerPublicKey();
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
// 获取服务器公钥
|
|
||||||
getServerPublicKey() {
|
|
||||||
// 先从本地存储获取
|
|
||||||
const storedPublicKey = localStorage.getItem(Constant.STORAGE_KEY.PUBLIC_KEY);
|
|
||||||
if (storedPublicKey) {
|
|
||||||
this.serverPublicKey = storedPublicKey;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 从公共配置接口获取公钥
|
|
||||||
Api.user.getPubConfig(
|
|
||||||
(res) => {
|
|
||||||
if (res.data && res.data.data && res.data.data.sm2PublicKey) {
|
|
||||||
this.serverPublicKey = res.data.data.sm2PublicKey;
|
|
||||||
// 存储到本地
|
|
||||||
localStorage.setItem(Constant.STORAGE_KEY.PUBLIC_KEY, this.serverPublicKey);
|
|
||||||
} else {
|
|
||||||
showDanger(this.$t('sm2.failedToGetPublicKey'));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
(err) => {
|
|
||||||
showDanger(this.$t('sm2.failedToGetPublicKey'));
|
|
||||||
}
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fetchCaptcha() {
|
fetchCaptcha() {
|
||||||
if (this.$store.getters.getToken) {
|
if (this.$store.getters.getToken) {
|
||||||
if (this.$route.path !== "/home") {
|
if (this.$route.path !== "/home") {
|
||||||
@@ -316,40 +285,12 @@ export default {
|
|||||||
if (!this.validateInput(this.form.captcha, 'login.requiredCaptcha')) {
|
if (!this.validateInput(this.form.captcha, 'login.requiredCaptcha')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查服务器公钥是否已获取,如果未获取则重新获取
|
|
||||||
if (!this.serverPublicKey) {
|
|
||||||
try {
|
|
||||||
// 等待公钥获取完成
|
|
||||||
await new Promise((resolve, reject) => {
|
|
||||||
this.getServerPublicKey();
|
|
||||||
// 设置超时检查,最多等待3秒
|
|
||||||
const checkInterval = setInterval(() => {
|
|
||||||
if (this.serverPublicKey) {
|
|
||||||
clearInterval(checkInterval);
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
}, 100);
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
clearInterval(checkInterval);
|
|
||||||
if (!this.serverPublicKey) {
|
|
||||||
reject(new Error('获取公钥超时'));
|
|
||||||
}
|
|
||||||
}, 3000);
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
showDanger(this.$t('sm2.failedToGetPublicKey'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 加密密码
|
// 加密密码
|
||||||
let encryptedPassword;
|
let encryptedPassword;
|
||||||
try {
|
try {
|
||||||
// 拼接验证码和密码
|
// 拼接验证码和密码
|
||||||
const captchaAndPassword = this.form.captcha + this.form.password;
|
const captchaAndPassword = this.form.captcha + this.form.password;
|
||||||
encryptedPassword = sm2Encrypt(this.serverPublicKey, captchaAndPassword);
|
encryptedPassword = sm2Encrypt(this.sm2PublicKey, captchaAndPassword);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("密码加密失败:", error);
|
console.error("密码加密失败:", error);
|
||||||
showDanger(this.$t('sm2.encryptionFailed'));
|
showDanger(this.$t('sm2.encryptionFailed'));
|
||||||
@@ -410,8 +351,7 @@ export default {
|
|||||||
.login-type-container {
|
.login-type-container {
|
||||||
margin: 10px 20px;
|
margin: 10px 20px;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: center;
|
||||||
align-items: center;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.title-language-dropdown {
|
.title-language-dropdown {
|
||||||
|
|||||||
@@ -45,7 +45,8 @@
|
|||||||
<div style="display: flex; align-items: center; margin-top: 20px; width: 100%; gap: 10px;">
|
<div style="display: flex; align-items: center; margin-top: 20px; width: 100%; gap: 10px;">
|
||||||
<div class="input-box" style="width: calc(100% - 130px); margin-top: 0;">
|
<div class="input-box" style="width: calc(100% - 130px); margin-top: 0;">
|
||||||
<img loading="lazy" alt="" class="input-icon" src="@/assets/login/shield.png" />
|
<img loading="lazy" alt="" class="input-icon" src="@/assets/login/shield.png" />
|
||||||
<el-input v-model="form.captcha" :placeholder="$t('register.captchaPlaceholder')" style="flex: 1;" />
|
<el-input v-model="form.captcha" :placeholder="$t('register.captchaPlaceholder')"
|
||||||
|
style="flex: 1;" />
|
||||||
</div>
|
</div>
|
||||||
<img loading="lazy" v-if="captchaUrl" :src="captchaUrl" alt="验证码"
|
<img loading="lazy" v-if="captchaUrl" :src="captchaUrl" alt="验证码"
|
||||||
style="width: 150px; height: 40px; cursor: pointer;" @click="fetchCaptcha" />
|
style="width: 150px; height: 40px; cursor: pointer;" @click="fetchCaptcha" />
|
||||||
@@ -56,7 +57,8 @@
|
|||||||
<div style="display: flex; align-items: center; margin-top: 20px; width: 100%; gap: 10px;">
|
<div style="display: flex; align-items: center; margin-top: 20px; width: 100%; gap: 10px;">
|
||||||
<div class="input-box" style="width: calc(100% - 130px); margin-top: 0;">
|
<div class="input-box" style="width: calc(100% - 130px); margin-top: 0;">
|
||||||
<img loading="lazy" alt="" class="input-icon" src="@/assets/login/phone.png" />
|
<img loading="lazy" alt="" class="input-icon" src="@/assets/login/phone.png" />
|
||||||
<el-input v-model="form.mobileCaptcha" :placeholder="$t('register.mobileCaptchaPlaceholder')" style="flex: 1;" maxlength="6" />
|
<el-input v-model="form.mobileCaptcha" :placeholder="$t('register.mobileCaptchaPlaceholder')"
|
||||||
|
style="flex: 1;" maxlength="6" />
|
||||||
</div>
|
</div>
|
||||||
<el-button type="primary" class="send-captcha-btn" :disabled="!canSendMobileCaptcha"
|
<el-button type="primary" class="send-captcha-btn" :disabled="!canSendMobileCaptcha"
|
||||||
@click="sendMobileCaptcha">
|
@click="sendMobileCaptcha">
|
||||||
@@ -70,13 +72,15 @@
|
|||||||
<!-- 密码输入框 -->
|
<!-- 密码输入框 -->
|
||||||
<div class="input-box">
|
<div class="input-box">
|
||||||
<img loading="lazy" alt="" class="input-icon" src="@/assets/login/password.png" />
|
<img loading="lazy" alt="" class="input-icon" src="@/assets/login/password.png" />
|
||||||
<el-input v-model="form.password" :placeholder="$t('register.passwordPlaceholder')" type="password" show-password />
|
<el-input v-model="form.password" :placeholder="$t('register.passwordPlaceholder')" type="password"
|
||||||
|
show-password />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 新增确认密码 -->
|
<!-- 新增确认密码 -->
|
||||||
<div class="input-box">
|
<div class="input-box">
|
||||||
<img loading="lazy" alt="" class="input-icon" src="@/assets/login/password.png" />
|
<img loading="lazy" alt="" class="input-icon" src="@/assets/login/password.png" />
|
||||||
<el-input v-model="form.confirmPassword" :placeholder="$t('register.confirmPasswordPlaceholder')" type="password" show-password />
|
<el-input v-model="form.confirmPassword" :placeholder="$t('register.confirmPasswordPlaceholder')"
|
||||||
|
type="password" show-password />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 验证码部分保持相同 -->
|
<!-- 验证码部分保持相同 -->
|
||||||
@@ -121,12 +125,10 @@
|
|||||||
<script>
|
<script>
|
||||||
import Api from '@/apis/api';
|
import Api from '@/apis/api';
|
||||||
import VersionFooter from '@/components/VersionFooter.vue';
|
import VersionFooter from '@/components/VersionFooter.vue';
|
||||||
import { getUUID, goToPage, showDanger, showSuccess, validateMobile, sm2Encrypt } from '@/utils';
|
import { getUUID, goToPage, showDanger, showSuccess, sm2Encrypt, validateMobile } from '@/utils';
|
||||||
import { mapState } from 'vuex';
|
import { mapState } from 'vuex';
|
||||||
import Constant from '@/utils/constant';
|
|
||||||
|
|
||||||
// 导入语言切换功能
|
// 导入语言切换功能
|
||||||
import { changeLanguage } from '@/i18n';
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'register',
|
name: 'register',
|
||||||
@@ -137,7 +139,8 @@ export default {
|
|||||||
...mapState({
|
...mapState({
|
||||||
allowUserRegister: state => state.pubConfig.allowUserRegister,
|
allowUserRegister: state => state.pubConfig.allowUserRegister,
|
||||||
enableMobileRegister: state => state.pubConfig.enableMobileRegister,
|
enableMobileRegister: state => state.pubConfig.enableMobileRegister,
|
||||||
mobileAreaList: state => state.pubConfig.mobileAreaList
|
mobileAreaList: state => state.pubConfig.mobileAreaList,
|
||||||
|
sm2PublicKey: state => state.pubConfig.sm2PublicKey,
|
||||||
}),
|
}),
|
||||||
canSendMobileCaptcha() {
|
canSendMobileCaptcha() {
|
||||||
return this.countdown === 0 && validateMobile(this.form.mobile, this.form.areaCode);
|
return this.countdown === 0 && validateMobile(this.form.mobile, this.form.areaCode);
|
||||||
@@ -158,7 +161,6 @@ export default {
|
|||||||
captchaUrl: '',
|
captchaUrl: '',
|
||||||
countdown: 0,
|
countdown: 0,
|
||||||
timer: null,
|
timer: null,
|
||||||
serverPublicKey: "", // 服务器公钥
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
@@ -171,38 +173,8 @@ export default {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.fetchCaptcha();
|
this.fetchCaptcha();
|
||||||
// 获取服务器公钥
|
|
||||||
this.getServerPublicKey();
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
// 获取服务器公钥
|
|
||||||
getServerPublicKey() {
|
|
||||||
// 先从本地存储获取
|
|
||||||
const storedPublicKey = localStorage.getItem(Constant.STORAGE_KEY.PUBLIC_KEY);
|
|
||||||
if (storedPublicKey) {
|
|
||||||
this.serverPublicKey = storedPublicKey;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 从公共配置接口获取公钥
|
|
||||||
Api.user.getPubConfig(
|
|
||||||
(res) => {
|
|
||||||
if (res.data && res.data.data && res.data.data.sm2PublicKey) {
|
|
||||||
this.serverPublicKey = res.data.data.sm2PublicKey;
|
|
||||||
// 存储到本地
|
|
||||||
localStorage.setItem(Constant.STORAGE_KEY.PUBLIC_KEY, this.serverPublicKey);
|
|
||||||
} else {
|
|
||||||
showDanger(this.$t('sm2.failedToGetPublicKey'));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
(err) => {
|
|
||||||
showDanger(this.$t('sm2.failedToGetPublicKey'));
|
|
||||||
}
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 复用验证码获取方法
|
// 复用验证码获取方法
|
||||||
fetchCaptcha() {
|
fetchCaptcha() {
|
||||||
this.form.captchaId = getUUID();
|
this.form.captchaId = getUUID();
|
||||||
@@ -302,40 +274,12 @@ export default {
|
|||||||
if (!this.validateInput(this.form.captcha, this.$t('register.requiredCaptcha'))) {
|
if (!this.validateInput(this.form.captcha, this.$t('register.requiredCaptcha'))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查服务器公钥是否已获取,如果未获取则重新获取
|
|
||||||
if (!this.serverPublicKey) {
|
|
||||||
try {
|
|
||||||
// 等待公钥获取完成
|
|
||||||
await new Promise((resolve, reject) => {
|
|
||||||
this.getServerPublicKey();
|
|
||||||
// 设置超时检查,最多等待3秒
|
|
||||||
const checkInterval = setInterval(() => {
|
|
||||||
if (this.serverPublicKey) {
|
|
||||||
clearInterval(checkInterval);
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
}, 100);
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
clearInterval(checkInterval);
|
|
||||||
if (!this.serverPublicKey) {
|
|
||||||
reject(new Error('获取公钥超时'));
|
|
||||||
}
|
|
||||||
}, 3000);
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
showDanger(this.$t('sm2.failedToGetPublicKey'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 加密
|
// 加密
|
||||||
let encryptedPassword;
|
let encryptedPassword;
|
||||||
try {
|
try {
|
||||||
// 拼接验证码和密码
|
// 拼接验证码和密码
|
||||||
const captchaAndPassword = this.form.captcha + this.form.password;
|
const captchaAndPassword = this.form.captcha + this.form.password;
|
||||||
encryptedPassword = sm2Encrypt(this.serverPublicKey, captchaAndPassword);
|
encryptedPassword = sm2Encrypt(this.sm2PublicKey, captchaAndPassword);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("密码加密失败:", error);
|
console.error("密码加密失败:", error);
|
||||||
showDanger(this.$t('sm2.encryptionFailed'));
|
showDanger(this.$t('sm2.encryptionFailed'));
|
||||||
|
|||||||
Reference in New Issue
Block a user