diff --git a/.env.development b/.env.development
index 4165644..4aa45e0 100644
--- a/.env.development
+++ b/.env.development
@@ -7,3 +7,14 @@ VITE_APP_ENV='development'
# 开发环境
VITE_API_BASE='https://demo.leapy.cn'
VITE_WS_URL='wss://demo.leapy.cn/ws'
+
+# SM2公钥
+VITE_RSA_PUBLIC_KEY='-----BEGIN PUBLIC KEY-----
+ MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgSGuTW9sIHkDCOcXe0Gk
+ euU82C9vGDaL569ChxdG3Ab4BCu1LqtGARMBeTW99amHbRbJE4/dzafUsGEh2rOq
+ /yb/qwKixtk1PWfrcqTuHJ8vmuj9MCQ0EIirKzc7lvGDUoIQuGAyQMQOTx2/iiDW
+ Kk50n1wtA4j8CITNuvZIXcfyKcPNtrgvBnhIuBVuZ7+X8oEjiO4nknVN2HrgeDK7
+ aQ4B43MR9rraqaupOv2l8Ua1nwMI3BtBdhQgXkjzMruHehL5+Bq4EHY01mCccUWv
+ 7YoL2R9Idu8KKxvMxypO1SffMGj3ViE4TvAQHU+eRrnXWDv2c7WCXSzSZUPfXalO
+ EwIDAQAB
+ -----END PUBLIC KEY-----'
diff --git a/.env.production b/.env.production
index 70bd6a7..9509830 100644
--- a/.env.production
+++ b/.env.production
@@ -7,3 +7,14 @@ VITE_APP_ENV='production'
# 生产环境
VITE_API_BASE='https://demo.leapy.cn'
VITE_WS_URL='wss://demo.leapy.cn/ws'
+
+# SM2公钥
+VITE_RSA_PUBLIC_KEY='-----BEGIN PUBLIC KEY-----
+ MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgSGuTW9sIHkDCOcXe0Gk
+ euU82C9vGDaL569ChxdG3Ab4BCu1LqtGARMBeTW99amHbRbJE4/dzafUsGEh2rOq
+ /yb/qwKixtk1PWfrcqTuHJ8vmuj9MCQ0EIirKzc7lvGDUoIQuGAyQMQOTx2/iiDW
+ Kk50n1wtA4j8CITNuvZIXcfyKcPNtrgvBnhIuBVuZ7+X8oEjiO4nknVN2HrgeDK7
+ aQ4B43MR9rraqaupOv2l8Ua1nwMI3BtBdhQgXkjzMruHehL5+Bq4EHY01mCccUWv
+ 7YoL2R9Idu8KKxvMxypO1SffMGj3ViE4TvAQHU+eRrnXWDv2c7WCXSzSZUPfXalO
+ EwIDAQAB
+ -----END PUBLIC KEY-----'
diff --git a/package.json b/package.json
index fb28a84..297e975 100644
--- a/package.json
+++ b/package.json
@@ -25,6 +25,7 @@
"element-plus": "2.13.0",
"highlight.js": "^11.11.1",
"image-conversion": "^2.1.1",
+ "jsencrypt": "^3.5.4",
"nprogress": "^0.2.0",
"pinia": "^3.0.4",
"pinia-plugin-persistedstate": "^4.7.1",
@@ -37,6 +38,7 @@
"xgplayer-hls": "^3.0.23"
},
"devDependencies": {
+ "@types/crypto-js": "^4.2.2",
"@types/node": "^25.0.3",
"@vitejs/plugin-vue": "^6.0.3",
"eslint": "^9.39.2",
diff --git a/src/config/index.ts b/src/config/index.ts
index b680265..f69dbfe 100644
--- a/src/config/index.ts
+++ b/src/config/index.ts
@@ -22,4 +22,6 @@ export default {
//布局 分栏:column | 通栏:header | 经典:menu | 功能坞:dock
//dock将关闭标签和面包屑栏
APP_LAYOUT: 'column',
+ // sm2公钥
+ RSA_PUBLIC_KEY: import.meta.env.VITE_RSA_PUBLIC_KEY
}
diff --git a/src/router/index.ts b/src/router/index.ts
index abaf6e4..6d23741 100644
--- a/src/router/index.ts
+++ b/src/router/index.ts
@@ -7,7 +7,7 @@ import tools from '@/utils/tools'
import api from "@/api"
import sRouter from './system'
import {treeFilter, filterAsyncRouter, flatAsyncRoutes} from '@/utils/route'
-import {beforeEach, afterEach} from '@/utils/route'
+import {beforeEach, afterEach, makeMenu} from '@/utils/route'
import i18n from "@/locales"
//系统路由
@@ -59,7 +59,7 @@ router.beforeEach(async (to, from, next) => {
/* @ts-ignore */
const res = await api.auth.menu()
/* @ts-ignore */
- tools.data.set("MENU", tools.makeMenu(res.data.menus, 0))
+ tools.data.set("MENU", makeMenu(res.data.menus, 0))
/* @ts-ignore */
tools.data.set("PERMISSIONS", res.data.buttons)
/* @ts-ignore */
@@ -72,7 +72,7 @@ router.beforeEach(async (to, from, next) => {
})
let menu = [...userMenu, ...apiMenu]
- var menuRouter = filterAsyncRouter(menu)
+ let menuRouter = filterAsyncRouter(menu);
menuRouter = flatAsyncRoutes(menuRouter)
menuRouter.forEach(item => {
router.addRoute("layout", item)
diff --git a/src/utils/route.ts b/src/utils/route.ts
index ed5402a..371ba6a 100644
--- a/src/utils/route.ts
+++ b/src/utils/route.ts
@@ -112,3 +112,29 @@ export function getMenu() {
})
return [...userMenu, ...apiMenu]
}
+
+export function makeMenu(menus, pid = 0) {
+ const arr = [];
+ for (let item of menus) {
+ if (item.pid === pid) {
+ // 数据格式处理
+ const tmp = {
+ name: item['name'],
+ path: item['type'] == 0 ? '/' + item['path'] : item['path'],
+ component: item['path'],
+ meta: {
+ 'title': item['title'],
+ 'icon': item['icon'],
+ 'hidden': item['hidden'],
+ 'type': item['type'] == 0 ? 'menu' : 'link'
+ }
+ };
+ const children = makeMenu(menus, item.menu_id);
+ if (children.length > 0) {
+ tmp['children'] = children
+ }
+ arr.push(tmp)
+ }
+ }
+ return arr
+}
diff --git a/src/utils/tools.ts b/src/utils/tools.ts
index 9fc034f..b036761 100644
--- a/src/utils/tools.ts
+++ b/src/utils/tools.ts
@@ -1,4 +1,6 @@
-import CryptoJS from 'crypto-js';
+import CryptoJS from 'crypto-js'
+import JSEncrypt from 'jsencrypt'
+import config from "@/config"
const tools = {
data: {
@@ -11,7 +13,9 @@ const tools = {
},
get(cacheKey: string) {
try {
- const cacheValue = JSON.parse(tools.base64.decrypt(localStorage.getItem(cacheKey)))
+ const data = localStorage.getItem(cacheKey);
+ if (!data) return null
+ const cacheValue = JSON.parse(tools.base64.decrypt(data))
if (cacheValue) {
let nowTime = new Date().getTime()
if (nowTime > cacheValue.expireIn && cacheValue.expireIn !== 0) {
@@ -48,36 +52,36 @@ const tools = {
return [null, err]
}
},
- crypto: {
- //MD5加密
- MD5(data: string) {
- return CryptoJS.MD5(data).toString()
- },
+ md5: function (data: string) {
+ return CryptoJS.MD5(data).toString()
},
- makeMenu: function (menus, pid = 0) {
- const arr = [];
- for (let item of menus) {
- if (item.pid === pid) {
- // 数据格式处理
- const tmp = {
- name: item['name'],
- path: item['type'] == 0 ? '/' + item['path'] : item['path'],
- component: item['path'],
- meta: {
- 'title': item['title'],
- 'icon': item['icon'],
- 'hidden': item['hidden'],
- 'type': item['type'] == 0 ? 'menu' : 'link'
- }
- };
- const children = this.makeMenu(menus, item.menu_id);
- if (children.length > 0) {
- tmp['children'] = children
- }
- arr.push(tmp)
- }
+ aes: {
+ encrypt(message: string, secretKey: string): string {
+ return CryptoJS.AES.encrypt(message, secretKey).toString()
+ },
+ decrypt(ciphertext: string, secretKey: string) {
+ CryptoJS.AES.decrypt(ciphertext, secretKey).toString(CryptoJS.enc.Utf8)
+ }
+ },
+ rsa: {
+ encrypt(message: string): string {
+ const encryptor = new JSEncrypt()
+ encryptor.setPublicKey(config.RSA_PUBLIC_KEY)
+ const encrypted = encryptor.encrypt(message)
+ if (!encrypted) {
+ throw new Error('RSA encrypt failed')
+ }
+ return encrypted;
+ },
+ decrypt(cipherText: string, privateKey: string): string {
+ const decryptor = new JSEncrypt()
+ decryptor.setPrivateKey(privateKey)
+ const decrypted = decryptor.decrypt(cipherText)
+ if (!decrypted) {
+ throw new Error('RSA decrypt failed')
+ }
+ return decrypted
}
- return arr
},
screen: function (element) {
var isFull = !!(document.webkitIsFullScreen || document.mozFullScreen || document.msFullscreenElement || document.fullscreenElement);
@@ -129,16 +133,13 @@ const tools = {
}
return fmt;
},
- randomUUIDString: function (len = 16) {
- return crypto.randomUUID().replace(/-/g, '').slice(0, len)
- },
makeTreeData: function (data, pid = 0, key = "id", parent = "parent_id") {
const arr = [];
for (let item of data) {
if (item[parent] == pid) {
// 数据格式处理
const tmp = item;
- const children = tools.makeTreeData(data, item[key], key, parent);
+ const children = this.makeTreeData(data, item[key], key, parent);
if (children.length > 0) {
tmp['children'] = children
}
@@ -147,6 +148,9 @@ const tools = {
}
return arr
},
+ randomUUIDString: function (len = 16) {
+ return crypto.randomUUID().replace(/-/g, '').slice(0, len)
+ },
getBrowser(userAgent: string) {
// 检测浏览器类型和版本
if (/Opera|OPR/.test(userAgent)) {
diff --git a/src/views/dashboard/message/detail.vue b/src/views/dashboard/message/detail.vue
deleted file mode 100644
index 05e3252..0000000
--- a/src/views/dashboard/message/detail.vue
+++ /dev/null
@@ -1,86 +0,0 @@
-
-
-
-
- 发布人:{{ info.nickname }}
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/views/system/login/index.vue b/src/views/system/login/index.vue
index 449c07a..53dc899 100644
--- a/src/views/system/login/index.vue
+++ b/src/views/system/login/index.vue
@@ -186,11 +186,11 @@ async function login() {
}
isLogin.value = true
const data = {
- username: form.value.username,
- password: tools.crypto.MD5(form.value.password),
+ username: tools.rsa.encrypt(form.value.username),
+ password: tools.rsa.encrypt(tools.md5(form.value.password)),
uuid: form.value.uuid,
- code: form.value.code
- };
+ code: tools.rsa.encrypt(form.value.code)
+ }
// 登录接口
const [res, err] = await tools.go(api.auth.login(data))
isLogin.value = false
diff --git a/tsconfig.json b/tsconfig.json
index 14bdc73..8a9d0fc 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,33 +1,13 @@
{
"compilerOptions": {
- "target": "ESNext",
- "useDefineForClassFields": true,
"module": "ESNext",
- "moduleResolution": "Bundler",
- "lib": [
- "ESNext",
- "DOM"
- ],
- "jsx": "preserve",
- "strict": true,
- "skipLibCheck": true,
- "types": [
- "node",
- "vite/client"
- ],
- "baseUrl": ".",
+ "moduleResolution": "node",
+ "types": ["node"],
+ "baseUrl": "./",
"paths": {
- "@/*": [
- "src/*"
- ]
+ "@/*": ["src/*"]
},
"esModuleInterop": true,
- "allowSyntheticDefaultImports": true,
- "ignoreDeprecations": "6.0"
- },
- "include": [
- "src/**/*.ts",
- "src/**/*.tsx",
- "src/**/*.vue"
- ]
+ "allowSyntheticDefaultImports": true
+ }
}
diff --git a/vite-env.d.ts b/vite-env.d.ts
index ca9eb6c..7399b62 100644
--- a/vite-env.d.ts
+++ b/vite-env.d.ts
@@ -12,6 +12,7 @@ interface ImportMetaEnv {
readonly VITE_APP_TITLE: string
readonly VITE_WS_URL: string,
readonly VITE_APP_ENV: string
+ readonly VITE_RSA_PUBLIC_KEY: string
}
interface Document {