feat: implement RSA encryption for login data and update authentication settings
Some checks are pending
sync2gitee / repo-sync (push) Waiting to run
Typos Check / Spell Check with Typos (push) Waiting to run

This commit is contained in:
wxg0103 2025-09-18 18:43:26 +08:00
parent 74c454532d
commit f06bdf3ee5
10 changed files with 31 additions and 14 deletions

View File

@ -27,7 +27,6 @@
"@wecom/jssdk": "^2.3.1",
"axios": "^1.8.4",
"cropperjs": "^1.6.2",
"crypto-js": "^4.2.0",
"dingtalk-jsapi": "^3.1.0",
"echarts": "^5.6.0",
"element-plus": "^2.10.2",
@ -42,6 +41,7 @@
"mermaid": "^10.9.0",
"moment": "^2.30.1",
"nanoid": "^5.1.5",
"node-forge": "^1.3.1",
"nprogress": "^0.2.0",
"pinia": "^3.0.1",
"recorder-core": "^1.3.25011100",
@ -64,6 +64,7 @@
"@types/crypto-js": "^4.2.2",
"@types/file-saver": "^2.0.7",
"@types/node": "^22.14.0",
"@types/node-forge": "^1.3.14",
"@types/nprogress": "^0.2.3",
"@vitejs/plugin-vue": "^5.2.3",
"@vitejs/plugin-vue-jsx": "^4.1.2",

View File

@ -12,6 +12,7 @@ interface ChatProfile {
// 登录类型
login_value?: Array<string>
max_attempts?: number
rasKey?: string
}
interface ChatUserProfile {

View File

@ -11,5 +11,9 @@ interface LoginRequest {
*
*/
captcha: string
/**
*
*/
encryptedData?: string
}
export type { LoginRequest }

View File

@ -94,7 +94,7 @@ const useChatUserStore = defineStore('chat-user', {
return this.token
})
},
login(request: LoginRequest, loading?: Ref<boolean>) {
login(request: any, loading?: Ref<boolean>) {
return ChatAPI.login(this.accessToken as string, request, loading).then((ok) => {
this.setToken(ok.data.token)
return this.token

View File

@ -16,7 +16,7 @@ const useLoginStore = defineStore('login', {
return localStorage.getItem('token')
},
async asyncLogin(data: LoginRequest, loading?: Ref<boolean>) {
async asyncLogin(data: any, loading?: Ref<boolean>) {
return LoginApi.login(data).then((ok) => {
this.token = ok?.data?.token
localStorage.setItem('token', ok?.data?.token)

View File

@ -16,7 +16,8 @@ export interface userStateTypes {
license_is_valid: boolean
edition: 'CE' | 'PE' | 'EE'
workspace_id: string
workspace_list: Array<any>
workspace_list: Array<any>,
rasKey: string
}
const useUserStore = defineStore('user', {
@ -27,6 +28,7 @@ const useUserStore = defineStore('user', {
edition: 'CE',
workspace_id: '',
workspace_list: [],
rasKey: '',
}),
actions: {
getLanguage() {
@ -140,6 +142,7 @@ const useUserStore = defineStore('user', {
this.license_is_valid = ok.data.license_is_valid
this.edition = ok.data.edition
this.version = ok.data.version
this.rasKey = ok.data.ras
const theme = useThemeStore()
if (this.isEE() || this.isPE()) {
await theme.theme()

View File

@ -180,7 +180,7 @@ import QrCodeTab from '@/views/chat/user-login/scanCompinents/QrCodeTab.vue'
import {MsgConfirm, MsgError} from '@/utils/message.ts'
import PasswordAuth from '@/views/chat/auth/component/password.vue'
import {isAppIcon} from '@/utils/common'
import CryptoJS from "crypto-js";
import forge from "node-forge";
useResize()
const router = useRouter()
@ -250,8 +250,13 @@ const loginHandle = () => {
})
})
} else {
loginForm.value.password = CryptoJS.MD5(loginForm.value.password.trim()).toString(CryptoJS.enc.Hex)
chatUser.login(loginForm.value).then((ok) => {
const publicKey = forge.pki.publicKeyFromPem(chatUser?.chat_profile?.rasKey as any);
const encrypted = publicKey.encrypt(JSON.stringify(loginForm.value), 'RSAES-PKCS1-V1_5');
const encryptedBase64 = forge.util.encode64(encrypted);
chatUser.login({
encryptedData: encryptedBase64,
username: loginForm.value.username
}).then((ok) => {
router.push({
name: 'chat',
params: {accessToken: chatUser.accessToken},

View File

@ -141,7 +141,7 @@ import QrCodeTab from '@/views/login/scanCompinents/QrCodeTab.vue'
import {MsgConfirm, MsgError} from '@/utils/message.ts'
import * as dd from 'dingtalk-jsapi'
import {loadScript} from '@/utils/common'
import CryptoJS from 'crypto-js';
import forge from 'node-forge';
const router = useRouter()
const {login, user, theme} = useStore()
@ -200,9 +200,11 @@ const loginHandle = () => {
loading.value = false
})
} else {
loginForm.value.password = CryptoJS.MD5(loginForm.value.password.trim()).toString(CryptoJS.enc.Hex)
const publicKey = forge.pki.publicKeyFromPem(user.rasKey);
const encrypted = publicKey.encrypt(JSON.stringify(loginForm.value), 'RSAES-PKCS1-V1_5');
const encryptedBase64 = forge.util.encode64(encrypted);
login
.asyncLogin(loginForm.value)
.asyncLogin({encryptedData: encryptedBase64, username: loginForm.value.username})
.then(() => {
locale.value = localStorage.getItem('MaxKB-locale') || getBrowserLang() || 'en-US'
localStorage.setItem('workspace_id', 'default')
@ -298,7 +300,7 @@ onBeforeMount(() => {
} else {
authSetting.value = {
max_attempts: 1,
default_value: 'password',
default_value: 'LOCAL',
}
}
const params = route.query
@ -315,7 +317,7 @@ onBeforeMount(() => {
} else {
authSetting.value = {
max_attempts: 1,
default_value: 'password',
default_value: 'LOCAL',
}
}
})
@ -351,7 +353,7 @@ const newDefaultSlogan = computed(() => {
})
function redirectAuth(authType: string, needMessage: boolean = true) {
if (authType === 'LDAP' || authType === '' || authType === 'password') {
if (authType === 'LDAP' || authType === '' || authType === 'LOCAL') {
return
}
authApi.getLoginViewAuthSetting(authType, loading).then((res: any) => {

View File

@ -84,7 +84,7 @@ const authFormRef = ref<FormInstance>();
const form = ref<any>({
default_value: 'password',
default_value: 'LOCAL',
max_attempts: 1,
})

View File

@ -171,6 +171,7 @@
:placeholder="
$t('views.applicationWorkflow.nodes.imageToVideoGenerate.last_frame.requiredMessage')
"
clearable
v-model="form_data.last_frame_url"
/>
</el-form-item>