Просмотр исходного кода

feat: 登录增加加密功能

yanglzh 1 год назад
Родитель
Сommit
f1799bada4
9 измененных файлов с 133 добавлено и 5 удалено
  1. 4 1
      .env
  2. 4 1
      .env.development
  3. 4 1
      .env.open
  4. 1 0
      package.json
  5. 1 0
      src/api/system/index.ts
  6. 15 0
      src/utils/rsa.ts
  7. 25 2
      src/views/login/component/account.vue
  8. 74 0
      src/views/login/component/changePwd.vue
  9. 5 0
      yarn.lock

+ 4 - 1
.env

@@ -25,4 +25,7 @@ VITE_TOPO_URL = '/plugin/topo/'
 # modbus服务
 VITE_MODBUS_API = '/base-api/modbus'
 # ice104协议网关服务
-VITE_ICE104_API = '/base-api/ice104'
+VITE_ICE104_API = '/base-api/ice104'
+
+# 加密公钥, 用双引号,换行符用 \n
+VITE_PUBLIC_KEY = "-----BEGIN PUBLIC KEY-----\nMIIBCgKCAQEA2GHtfmjFVCi5pcjsv6ppyeEmESN4FpID8WHLtvXXRm3wexonVmhO\n2GUEl/T8PonnYYuUHARFVBmTEF0SvFUwfTab88HznL8KDW8yPDEz8E8daV59BzAx\nVWP389PUxv0AAwLWNa5dy5cIG4eKvrgRjHtMn/c12Ba5R6OfvWX/lX9YkOIDfeca\n2X1eOhgtfqVr4iG6R4UHAf0NzKleNvPbwQjXUN/wMFIF7bNmYebn5kSBDkFb2DLP\npEb8iQ6CQzQM/Z6HVGM2XokJ2oPhvUFpI7BVQce0gIg7rq00Dexz7IJxCU/khkFY\nR6fjPEkL0hoaae2MXtv22gJPwOhlh7kFhQIDAQAB\n-----END PUBLIC KEY-----"

+ 4 - 1
.env.development

@@ -11,4 +11,7 @@ VITE_SERVER_HOSTNAME = 'zhgy.sagoo.cn'
 # VITE_SERVER_HOSTNAME = 'liangzi.server.mydig.net'
 
 # VITE_SERVER_PROTOCOL = 'http:'
-# VITE_SERVER_HOSTNAME = 'pg.server.mydig.net'
+# VITE_SERVER_HOSTNAME = 'pg.server.mydig.net'
+
+# 加密公钥, 用双引号,换行符用 \n
+VITE_PUBLIC_KEY = "-----BEGIN PUBLIC KEY-----\nMIIBCgKCAQEAvp4tyTMi9aWjzm75Mbv00ztx7vIMgOE/8UyMCRPR7uYFCccklXk2\nt0bDwm21OtPF6L+xb9p1vEPVM8NmCUYoGMMb/alwFy0rF0mjH6+vw2Ui1nd+O7P1\nYDcYyj/k+bZFBaPIgfX14gel1apTd39L4DaiLR6mn3uQJd7n2X0GfD1PctmI/Ecx\ndPOzf7119fEk13f7g1w2wllIppb8ewsI2tiewORBqxwJLtDQE+TmYJLHFRSCbUls\nGYlXTpNNVHC0l/C63EwEk7EyGXom/O9Izsqjtbz7DMCkSz8we2aaLzywP3goEhfT\n8THh/M4CptdHMJINUh8HvMbLaE7flnaUZQIDAQAB\n-----END PUBLIC KEY-----"

+ 4 - 1
.env.open

@@ -1,4 +1,7 @@
 VITE_SERVER_PROTOCOL = ''
 VITE_SERVER_HOSTNAME = ''
 # 开源标识
-VITE_ISOPEN = true
+VITE_ISOPEN = true
+
+# 加密公钥, 用双引号,换行符用 \n
+VITE_PUBLIC_KEY = "-----BEGIN PUBLIC KEY-----\nMIIBCgKCAQEAvp4tyTMi9aWjzm75Mbv00ztx7vIMgOE/8UyMCRPR7uYFCccklXk2\nt0bDwm21OtPF6L+xb9p1vEPVM8NmCUYoGMMb/alwFy0rF0mjH6+vw2Ui1nd+O7P1\nYDcYyj/k+bZFBaPIgfX14gel1apTd39L4DaiLR6mn3uQJd7n2X0GfD1PctmI/Ecx\ndPOzf7119fEk13f7g1w2wllIppb8ewsI2tiewORBqxwJLtDQE+TmYJLHFRSCbUls\nGYlXTpNNVHC0l/C63EwEk7EyGXom/O9Izsqjtbz7DMCkSz8we2aaLzywP3goEhfT\n8THh/M4CptdHMJINUh8HvMbLaE7flnaUZQIDAQAB\n-----END PUBLIC KEY-----"

+ 1 - 0
package.json

@@ -33,6 +33,7 @@
     "echarts-wordcloud": "^2.0.0",
     "element-plus": "2.2.28",
     "event-source-polyfill": "^1.0.31",
+    "jsencrypt": "^3.3.2",
     "jsplumb": "^2.15.6",
     "mitt": "^3.0.0",
     "nprogress": "^0.2.0",

+ 1 - 0
src/api/system/index.ts

@@ -5,6 +5,7 @@ export default {
   login: {
     login: (data: object) => post('/login', data),
     currentUser: () => get('/system/user/currentUser'),
+    editPassword: (data: object) => post('/user/editPassword', data),
     captcha: () => get('/captcha'),
     logout: () => post('/loginOut'),
   },

+ 15 - 0
src/utils/rsa.ts

@@ -0,0 +1,15 @@
+import JSEncrypt from 'jsencrypt'
+
+export function encrypt(value: string) {
+  const crypt = new JSEncrypt();
+  crypt.setPublicKey(import.meta.env.VITE_PUBLIC_KEY);
+  return crypt.encrypt(value)
+}
+
+export function decrypt(value: string) {
+  const crypt = new JSEncrypt();
+  crypt.setPrivateKey(import.meta.env.VITE_PRIVATE_KEY);
+  return crypt.decrypt(value)
+}
+
+// console.log(decrypt('GyFOsw70nGTQD/tnI5o2pOnJxQKH2MEsG8jL2ZxFP+nLkEpB8puahImT7cs2yjGK8dc78WPKev2N2zwypbVDG3A/31GctX38tYF2ivBO4c+XZyGuYwQSLEidDv3XqV3MrXwNLksYeIKKEwPBHD52nrWwZKvyK0LeLeaBCrRQmLV7kfhLh6bGKhe9n5Yjiwu+1GsgWpUa4ht4WwFf5og+tNCaI99IQoxpNdhHA2UtrtbgVcNZ8o2/d5aSE7g9ScvGaH0rMNfLc25UezltxTzEMSWv/8DGg7yL844U97qXwRWBGS5oi0Da9UtvGMegEjBLqBGSztGBB/LeQDzu9KyAQQ=='))

+ 25 - 2
src/views/login/component/account.vue

@@ -44,12 +44,14 @@
 				<span>{{ $t('message.account.accountBtnText') }}</span>
 			</el-button>
 		</el-form-item>
+		<changePwd ref="changePwdRef"></changePwd>
 	</el-form>
 </template>
 
 <script lang="ts">
-import { toRefs, reactive, defineComponent, computed, onMounted, getCurrentInstance } from 'vue';
+import { ref, toRefs, reactive, defineComponent, computed, onMounted, getCurrentInstance } from 'vue';
 import { useRoute, useRouter } from 'vue-router';
+import changePwd from './changePwd.vue';
 import { ElMessage } from 'element-plus';
 import { useI18n } from 'vue-i18n';
 import { initFrontEndControlRoutes } from '/@/router/frontEnd';
@@ -57,6 +59,7 @@ import { initBackEndControlRoutes } from '/@/router/backEnd';
 import { useStore } from '/@/store/index';
 import { Session, Local } from '/@/utils/storage';
 import { formatAxis } from '/@/utils/formatTime';
+import { encrypt } from '/@/utils/rsa'
 import api from '/@/api/system';
 
 // 是否是开源版本
@@ -64,7 +67,11 @@ const ISOPEN = import.meta.env.VITE_ISOPEN
 
 export default defineComponent({
 	name: 'loginAccount',
+	components: {
+		changePwd
+	},
 	setup() {
+		const changePwdRef = ref();
 		const { t } = useI18n();
 		const store = useStore();
 		const route = useRoute();
@@ -111,8 +118,23 @@ export default defineComponent({
 					if (valid) {
 						state.loading.signIn = true;
 						api.login
-							.login(state.ruleForm)
+							.login({
+								...state.ruleForm,
+								password: encrypt(state.ruleForm.password)
+							})
 							.then(async (res: any) => {
+								// 检查是否需要更换密码
+								if (res.isChangePwd) {
+									const sysinfo = JSON.parse(localStorage.sysinfo || '{}');
+									ElMessage.error(`密码已超过${sysinfo.passwordChangePeriod}天未修改,请先修改密码再登录`)
+									state.loading.signIn = false;
+									getCaptcha();
+									return changePwdRef.value.toShow({
+										userName: state.ruleForm.userName,
+										oldUserPassword: state.ruleForm.password,
+									})
+								}
+
 								const userInfos = res.userInfo;
 								userInfos.avatar = proxy.getUpFileUrl(userInfos.avatar);
 								// 存储 token 到浏览器缓存
@@ -182,6 +204,7 @@ export default defineComponent({
 			ElMessage.success(`${currentTimeInfo},${signInText}`);
 		};
 		return {
+			changePwdRef,
 			onSignIn,
 			getCaptcha,
 			...toRefs(state),

+ 74 - 0
src/views/login/component/changePwd.vue

@@ -0,0 +1,74 @@
+<template>
+	<el-dialog title="更新密码" v-model="show" width="500px" :show-close="false" destroy-on-close :close-on-click-modal="false" :close-on-press-escape="false">
+		<el-form ref="formRef" :model="ruleForm" :rules="formRules">
+			<el-form-item prop="userName">
+				<el-input type="text" placeholder="请输入用户名" v-model="ruleForm.userName" clearable autocomplete="off">
+					<template #prefix><el-icon><ele-User /></el-icon></template>
+				</el-input>
+			</el-form-item>
+			<el-form-item class="login-animation2" prop="oldUserPassword">
+				<el-input :type="isShowPassword1 ? 'text' : 'password'" placeholder="请输入旧密码" v-model="ruleForm.oldUserPassword" autocomplete="off">
+					<template #prefix><el-icon><ele-Unlock /></el-icon></template>
+					<template #suffix><i class="iconfont" :class="isShowPassword1 ? 'icon-yincangmima' : 'icon-xianshimima'" @click="isShowPassword1 = !isShowPassword1"></i></template>
+				</el-input>
+			</el-form-item>
+			<el-form-item class="login-animation2" prop="userPassword">
+				<!--suppress TypeScriptValidateTypes -->
+				<el-input :type="isShowPassword2 ? 'text' : 'password'" placeholder="请输入新密码" v-model="ruleForm.userPassword" autocomplete="off">
+					<template #prefix><el-icon><ele-Unlock /></el-icon></template>
+					<template #suffix><i class="iconfont" :class="isShowPassword2 ? 'icon-yincangmima' : 'icon-xianshimima'" @click="isShowPassword2 = !isShowPassword2"></i></template>
+				</el-input>
+			</el-form-item>
+		</el-form>
+		<template #footer>
+			<el-button type="primary" @click="onSubmit" size="default">更 换</el-button>
+		</template>
+	</el-dialog>
+</template>
+
+<script lang="ts" setup>
+import { computed, reactive, ref } from "vue";
+import { encrypt } from '/@/utils/rsa'
+import api from '/@/api/system';
+import { ElMessage } from "element-plus";
+
+const formRef = ref()
+const show = ref(false)
+const isShowPassword1 = ref(false)
+const isShowPassword2 = ref(false)
+
+const ruleForm = reactive({
+	userName: '',
+	oldUserPassword: '',
+	userPassword: '',
+})
+
+const formRules = computed(() => ({
+	userName: [{ required: true, trigger: 'change', message: '用户名不能为空' }],
+	oldUserPassword: [{ required: true, trigger: 'change', message: '旧密码不能为空' }],
+	userPassword: [{ required: true, trigger: 'change', message: '新密码不能为空' }],
+}))
+
+async function onSubmit() {
+	await formRef.value.validate()
+
+	api.login.editPassword({
+		userName: ruleForm.userName,
+		oldUserPassword: encrypt(ruleForm.oldUserPassword),
+		userPassword: encrypt(ruleForm.userPassword)
+	}).then(() => {
+		show.value = false
+		ElMessage.success('修改成功')
+	})
+
+}
+function toShow(data: any) {
+	ruleForm.userName = data.userName
+	ruleForm.oldUserPassword = data.oldUserPassword
+	show.value = true
+}
+
+defineExpose({ toShow })
+</script>
+
+<style scoped lang="scss"></style>

+ 5 - 0
yarn.lock

@@ -2096,6 +2096,11 @@ js-yaml@^4.1.0:
   dependencies:
     argparse "^2.0.1"
 
+jsencrypt@^3.3.2:
+  version "3.3.2"
+  resolved "https://registry.yarnpkg.com/jsencrypt/-/jsencrypt-3.3.2.tgz#b0f1a2278810c7ba1cb8957af11195354622df7c"
+  integrity sha512-arQR1R1ESGdAxY7ZheWr12wCaF2yF47v5qpB76TtV64H1pyGudk9Hvw8Y9tb/FiTIaaTRUyaSnm5T/Y53Ghm/A==
+
 json-schema-traverse@^0.4.1:
   version "0.4.1"
   resolved "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz"