diff --git a/sgzb-ui/src/router/index.js b/sgzb-ui/src/router/index.js index 7d0a4c78..ce83fd72 100644 --- a/sgzb-ui/src/router/index.js +++ b/sgzb-ui/src/router/index.js @@ -105,9 +105,12 @@ export const constantRoutes = [ path: '/qrCode/qrCodePage', component: () => import('@/views/qrCode/qrCode'), hidden: true - - - } + }, + { + path: '/resetPassword', + component: () => import('@/views/resetPassword'), + hidden: true + }, ] // 动态路由,基于用户权限动态去加载 diff --git a/sgzb-ui/src/store/modules/user.js b/sgzb-ui/src/store/modules/user.js index 5f33664a..01d388a9 100644 --- a/sgzb-ui/src/store/modules/user.js +++ b/sgzb-ui/src/store/modules/user.js @@ -72,6 +72,7 @@ const user = { return new Promise((resolve, reject) => { login(username, password, code, uuid).then(res => { let data = res.data + localStorage.setItem('isCode', data.code) setToken(data.access_token) commit('SET_TOKEN', data.access_token) localStorage.setItem('token', data.access_token) diff --git a/sgzb-ui/src/utils/validate.js b/sgzb-ui/src/utils/validate.js index adfa2542..9b5804fb 100644 --- a/sgzb-ui/src/utils/validate.js +++ b/sgzb-ui/src/utils/validate.js @@ -81,3 +81,14 @@ export function isArray(arg) { } return Array.isArray(arg) } + +/** + * @param {string} str + * @returns {Boolean} + */ + +// 密码规则:8-20位,必须包含字母、数字、特殊字符中的两种 +export function validPassword(str) { + const reg = /^((?=.*[A-Za-z])(?=.*\d)|(?=.*[A-Za-z])(?=.*[!@#$%^&*()_+\-\=])|(?=.*\d)(?=.*[!@#$%^&*()_+\-\=]))[A-Za-z\d!@#$%^&*()_+\-\=]{8,20}$/ + return reg.test(str) +} \ No newline at end of file diff --git a/sgzb-ui/src/views/login.vue b/sgzb-ui/src/views/login.vue index 1855ded1..c004f900 100644 --- a/sgzb-ui/src/views/login.vue +++ b/sgzb-ui/src/views/login.vue @@ -302,8 +302,11 @@ export default { Cookies.remove('rememberMe'); } this.$store.dispatch("Login", this.loginForm).then(() => { - this.$router.push({path:"/"}).catch(() => { - }); + if (localStorage.getItem('isCode') == 1) { + this.$router.push({ path: '/resetPassword' }).catch(() => {}) + } else { + this.$router.push({ path: '/' }).catch(() => {}) + } }).catch(() => { this.loading = false; if (this.captchaEnabled) { diff --git a/sgzb-ui/src/views/resetPassword.vue b/sgzb-ui/src/views/resetPassword.vue new file mode 100644 index 00000000..b6f01594 --- /dev/null +++ b/sgzb-ui/src/views/resetPassword.vue @@ -0,0 +1,246 @@ + + + + + 请重置登录密码 + + + + + + + + + + + + 确认修改 + 返回登录页 + + + + + + + + + + diff --git a/sgzb-ui/src/views/system/config/index.vue b/sgzb-ui/src/views/system/config/index.vue index d9f28ecb..ad0a9e2a 100644 --- a/sgzb-ui/src/views/system/config/index.vue +++ b/sgzb-ui/src/views/system/config/index.vue @@ -240,6 +240,15 @@ export default { getList() { this.loading = true; listConfig(this.addDateRange(this.queryParams, this.dateRange)).then(response => { + response.rows.forEach(row => { + if (row.configKey == 'sys.user.initPassword') { + this.decryptData(row.configValue, 'CCNXrpassWordKey').then(data => { + row.configValue = data; + }).catch(err => { + console.log('🚀 ~ decryptData ~ err:', err); + }); + } + }); this.configList = response.rows; this.total = response.total; this.loading = false; @@ -337,6 +346,26 @@ export default { refreshCache().then(() => { this.$modal.msgSuccess("刷新成功"); }); + }, + async decryptData(encryptedData, keyStr) { + const keyUint8 = new TextEncoder().encode(keyStr); + const encryptedBytes = Uint8Array.from(atob(encryptedData), c => c.charCodeAt(0)); + + const key = await crypto.subtle.importKey( + 'raw', + keyUint8, + { name: 'AES-CBC', length: 256 }, // 假设后端使用了CBC模式,需要调整为实际使用的模式 + false, + ['decrypt'] + ); + + const decryptedData = await crypto.subtle.decrypt( + { name: 'AES-CBC', iv: new Uint8Array(16) }, // 实际使用时需要正确的IV,这里仅为示例 + key, + encryptedBytes + ); + + return new TextDecoder().decode(decryptedData); } } }; diff --git a/sgzb-ui/src/views/system/user/index.vue b/sgzb-ui/src/views/system/user/index.vue index 7e4caabe..466b66b1 100644 --- a/sgzb-ui/src/views/system/user/index.vue +++ b/sgzb-ui/src/views/system/user/index.vue @@ -345,6 +345,7 @@ import { listUser, getUser, delUser, addUser, updateUser, resetUserPwd, changeUs import { getToken } from "@/utils/auth"; import Treeselect from "@riophae/vue-treeselect"; import "@riophae/vue-treeselect/dist/vue-treeselect.css"; +import { validPassword } from '@/utils/validate' export default { name: "User", @@ -436,7 +437,22 @@ export default { ], password: [ { required: true, message: "用户密码不能为空", trigger: "blur" }, - { min: 5, max: 20, message: '用户密码长度必须介于 5 和 20 之间', trigger: 'blur' } + { min: 8, max: 20, message: '用户密码长度必须介于 8 和 20 之间', trigger: 'blur' }, + { + required: true, + validator: (rule, value, callback) => { + if (!validPassword(value)) { + callback( + new Error( + '密码须包含数字、字母、特殊符号中的两种以上', + ) + ) + } else { + callback() + } + }, + trigger: 'blur', + } ], email: [ { @@ -452,7 +468,8 @@ export default { trigger: "blur" } ] - } + }, + secretKey: 'CCNXrpassWordKey' }; }, watch: { @@ -465,7 +482,12 @@ export default { this.getList(); this.getDeptTree(); this.getConfigKey("sys.user.initPassword").then(response => { - this.initPassword = response.msg; + this.decryptData(response.msg, this.secretKey).then((data) => { + console.log('🚀 ~ this.getConfigKey ~ data:', data) + this.initPassword = data + }).catch((error) => { + console.log('🚀 ~ this.getConfigKey ~ error:', error) + }) }); }, methods: { @@ -672,6 +694,27 @@ export default { // 提交上传文件 submitFileForm() { this.$refs.upload.submit(); + }, + // 解密 + async decryptData(encryptedData, keyStr) { + const keyUint8 = new TextEncoder().encode(keyStr); + const encryptedBytes = Uint8Array.from(atob(encryptedData), c => c.charCodeAt(0)); + + const key = await crypto.subtle.importKey( + 'raw', + keyUint8, + { name: 'AES-CBC', length: 256 }, + false, + ['decrypt'] + ); + + const decryptedData = await crypto.subtle.decrypt( + { name: 'AES-CBC', iv: new Uint8Array(16) }, + key, + encryptedBytes + ); + + return new TextDecoder().decode(decryptedData); } } }; diff --git a/sgzb-ui/src/views/system/user/profile/resetPwd.vue b/sgzb-ui/src/views/system/user/profile/resetPwd.vue index 402b9d6e..3dd669ec 100644 --- a/sgzb-ui/src/views/system/user/profile/resetPwd.vue +++ b/sgzb-ui/src/views/system/user/profile/resetPwd.vue @@ -18,15 +18,17 @@