登录流程

This commit is contained in:
刘玉霞 2024-06-19 10:56:57 +08:00
parent 7ab97a1377
commit e66a9523b2
11 changed files with 106 additions and 87 deletions

View File

@ -5,7 +5,7 @@ ENV = 'development'
VITE_BASE_PATH = './'
# 代理配置(开发使用),必须在一行中
VITE_APP_PROXY=[["/api","https://usp2.jsspisoft.com/api"]]
VITE_APP_PROXY=[["/api","http://192.168.130.12:8080/api"]]
# 开发环境下跨域代理请输入要跨域的api地址 - 尾部无需带'/'
# VITE_PROXY_URL = 'http://localhost:8000'

View File

@ -19,7 +19,6 @@
"element-plus": "2.7.4",
"esno": "4.7.0",
"font-awesome": "4.7.0",
"jsencrypt": "^3.3.2",
"lodash-es": "4.17.21",
"mitt": "3.0.1",
"nprogress": "0.2.0",

View File

@ -1,5 +1,4 @@
import createAxios from '/@/utils/axios'
import { useAdminInfo } from '/@/stores/adminInfo'
export function index() {
return createAxios({
@ -15,18 +14,17 @@ export function userinfo() {
})
}
export function login(method: 'get' | 'post', params: object = {}) {
export function login(params: object = {}) {
return createAxios({
url: '/api/auth/token/invoke',
url: '/api/auth/login',
data: params,
method: method,
method: 'POST',
})
}
export function logout() {
// const adminInfo = useAdminInfo()
return createAxios({
url: '/api/auth/token/revoke',
url: '/api/auth/logout',
method: 'POST',
})
}

View File

@ -27,8 +27,8 @@ export const changeTerminalConfigUrl = '/admin/ajax/changeTerminalConfig'
export const clearCacheUrl = '/admin/ajax/clearCache'
// 公共
export const captchaUrl = '/api/common/captcha'
export const clickCaptchaUrl = '/api/common/clickCaptcha'
export const captchaUrl = '/api/captchaImage'
export const clickCaptchaUrl = '/api/captchaImage'
export const checkClickCaptchaUrl = '/api/common/checkClickCaptcha'
export const refreshTokenUrl = '/api/common/refreshToken'
@ -218,13 +218,10 @@ export function buildCaptchaUrl() {
return getUrl() + captchaUrl + '?server=1'
}
export function getCaptchaData(id: string) {
export function getCaptchaData() {
return createAxios({
url: clickCaptchaUrl,
method: 'get',
params: {
id,
},
method: 'post',
})
}

View File

@ -87,11 +87,11 @@ const state: {
const load = () => {
state.loading = true
getCaptchaData(props.uuid).then((res) => {
getCaptchaData().then((res) => {
state.xy = []
state.tip = ''
state.loading = false
state.captcha = res.data
state.captcha.base64 = 'data:image\/png;base64,' + res.data.img
})
}

View File

@ -1,6 +1,7 @@
export default {
'Please enter an account': '请输入账号',
'Please input a password': '请输入密码',
'Please input a captcha': '请输入验证码',
'Hold session': '保持会话',
'Sign in': '登录',
}

View File

@ -160,7 +160,6 @@ const onAdminInfo = () => {
const onLogout = () => {
logout().then(() => {
debugger
Local.remove(ADMIN_INFO)
router.go(0)
})

View File

@ -1407,35 +1407,35 @@ const init = () => {
/**
* 后台初始化请求获取站点配置动态路由等信息
*/
index().then((res) => {
// siteConfig.dataFill(res.data.siteConfig)
// terminal.changePort(res.data.terminal.installServicePort)
// terminal.changePackageManager(res.data.terminal.npmPackageManager)
// siteConfig.setInitialize(true)
// index().then((res) => {
// siteConfig.dataFill(res.data.siteConfig)
// terminal.changePort(res.data.terminal.installServicePort)
// terminal.changePackageManager(res.data.terminal.npmPackageManager)
// siteConfig.setInitialize(true)
// if (!isEmpty(res.data.adminInfo)) {
// adminInfo.dataFill(res.data.adminInfo)
// siteConfig.setUserInitialize(true)
// }
// if (!isEmpty(res.data.adminInfo)) {
// adminInfo.dataFill(res.data.adminInfo)
// siteConfig.setUserInitialize(true)
// }
if (res.data) {
handleAdminRoute(menu)
// if (res.data) {
handleAdminRoute(menu)
//
if (route.params.to) {
const lastRoute = JSON.parse(route.params.to as string)
if (lastRoute.path != adminBaseRoutePath) {
let query = !isEmpty(lastRoute.query) ? lastRoute.query : {}
routePush({ path: lastRoute.path, query: query })
return
}
}
//
let firstRoute = getFirstRoute(navTabs.state.tabsViewRoutes)
if (firstRoute) routePush(firstRoute.path)
//
if (route.params.to) {
const lastRoute = JSON.parse(route.params.to as string)
if (lastRoute.path != adminBaseRoutePath) {
let query = !isEmpty(lastRoute.query) ? lastRoute.query : {}
routePush({ path: lastRoute.path, query: query })
return
}
})
}
//
let firstRoute = getFirstRoute(navTabs.state.tabsViewRoutes)
if (firstRoute) routePush(firstRoute.path)
// }
// })
}
const onAdaptiveLayout = () => {

View File

@ -90,10 +90,14 @@ function createAxios<Data = any, T = ApiPromise<Data>>(axiosConfig: AxiosRequest
if (config.method === 'post' && config.data) {
// 对data进行加密
config.data = encrypt_aes(config.data, v)
const formData = new FormData()
formData.append('param', encrypt_aes(config.data, v))
config.data = formData
} else if (config.method === 'get' && config.params) {
// 对params进行加密
config.params = encrypt_aes(config.params, v)
const formData = new FormData()
formData.append('param', encrypt_aes(config.params, v))
config.params = formData
}
// 自动携带token

View File

@ -1,35 +1,38 @@
import CryptoJS from 'crypto-js'
const key = ''
const key = 'b6967ee87b86d85a'
export function encrypt_aes(plaintText: string, iv: string) {
const encryptedData = CryptoJS.AES.encrypt(plaintText, key, {
export function encrypt_aes(text: any, iv: string) {
let plaintText = text
if (typeof text == 'object') {
plaintText = JSON.stringify(plaintText)
}
iv = CryptoJS.enc.Utf8.parse(iv)
let pkey = CryptoJS.enc.Utf8.parse(key)
plaintText = CryptoJS.enc.Utf8.parse(plaintText)
const encryptedData = CryptoJS.AES.encrypt(plaintText, pkey, {
iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
padding: CryptoJS.pad.ZeroPadding,
})
// const encryptedBase64Str = encryptedData.toString()
// // 需要读取encryptedData上的ciphertext.toString()才能拿到跟Java一样的密文
// const encryptedStr = encryptedData.ciphertext.toString()
const encryptedStr = encryptedData.ciphertext.toString(CryptoJS.enc.Base64)
return encryptedData.toString(CryptoJS.format.Base64)
return encryptedStr
}
export function decrypt_aes(word: string, iv: string) {
var decrypt = CryptoJS.AES.decrypt(word, key, {
iv = CryptoJS.enc.Utf8.parse(iv)
let pkey = CryptoJS.enc.Utf8.parse(key)
const decrypt = CryptoJS.AES.decrypt(word, pkey, {
iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
padding: CryptoJS.pad.ZeroPadding,
})
//解密后需要按照Utf8的方式将明文转位字符串
var decryptedStr = decrypt.toString(CryptoJS.enc.Utf8)
return decryptedStr
return decrypt.toString(CryptoJS.enc.Utf8)
}
export function generateRandomNumber(length: number) {

View File

@ -50,7 +50,23 @@
</template>
</el-input>
</el-form-item>
<el-checkbox v-model="form.keep" :label="t('login.Hold session')" size="default"></el-checkbox>
<el-form-item v-if="state.showCaptcha" prop="captcha">
<el-space>
<el-input
ref="captchaRef"
v-model="form.code"
type="text"
:placeholder="t('login.Please input a captcha')"
clearable
>
<template #prefix>
<Icon name="fa fa-unlock-alt" class="form-item-icon" size="16" color="var(--el-input-icon-color)" />
</template>
</el-input>
<img class="captcha-img" @click.prevent="load()" :src="state.captcha" />
</el-space>
</el-form-item>
<!-- <el-checkbox v-model="form.keep" :label="t('login.Hold session')" size="default"></el-checkbox> -->
<el-form-item>
<el-button
:loading="state.submitLoading"
@ -73,6 +89,7 @@
<script setup lang="ts">
import { onMounted, onBeforeUnmount, reactive, ref, nextTick } from 'vue'
import { getCaptchaData } from '/@/api/common'
import * as pageBubble from '/@/utils/pageBubble'
import type { FormInstance, InputInstance } from 'element-plus'
import { useI18n } from 'vue-i18n'
@ -80,10 +97,9 @@ import { editDefaultLang } from '/@/lang/index'
import { useConfig } from '/@/stores/config'
import { useAdminInfo } from '/@/stores/adminInfo'
import { login } from '/@/api/backend'
import { uuid } from '/@/utils/random'
import { buildValidatorData } from '/@/utils/validate'
import router from '/@/router'
import clickCaptcha from '/@/components/clickCaptcha'
// import clickCaptcha from '/@/components/clickCaptcha'
import toggleDark from '/@/utils/useDark'
import { fullUrl } from '/@/utils/common'
import { adminBaseRoutePath } from '/@/router/static/adminBase'
@ -97,16 +113,18 @@ toggleDark(config.layout.isDark)
const formRef = ref<FormInstance>()
const usernameRef = ref<InputInstance>()
const passwordRef = ref<InputInstance>()
const captchaRef = ref<InputInstance>()
const state = reactive({
showCaptcha: false,
showCaptcha: true,
submitLoading: false,
captcha: '',
})
const form = reactive({
username: '',
password: '',
keep: false,
captchaId: uuid(),
captchaInfo: '',
uuid: '',
code: '',
})
const { t } = useI18n()
@ -115,6 +133,7 @@ const { t } = useI18n()
const rules = reactive({
username: [buildValidatorData({ name: 'required', message: t('login.Please enter an account') }), buildValidatorData({ name: 'account' })],
password: [buildValidatorData({ name: 'required', message: t('login.Please input a password') }), buildValidatorData({ name: 'password' })],
code: [buildValidatorData({ name: 'required', message: t('login.Please input a captcha') }), buildValidatorData({ name: 'required' })],
})
const focusInput = () => {
@ -122,6 +141,8 @@ const focusInput = () => {
usernameRef.value!.focus()
} else if (form.password === '') {
passwordRef.value!.focus()
} else if (form.code === '') {
captchaRef.value!.focus()
}
}
@ -129,7 +150,7 @@ onMounted(() => {
timer = window.setTimeout(() => {
pageBubble.init()
}, 1000)
load()
// login('get')
// .then((res) => {
// state.showCaptcha = res.data.captcha
@ -148,34 +169,30 @@ onBeforeUnmount(() => {
const onSubmitPre = () => {
formRef.value?.validate((valid) => {
if (valid) {
if (state.showCaptcha) {
clickCaptcha(form.captchaId, (captchaInfo: string) => onSubmit(captchaInfo))
} else {
onSubmit()
}
// if (state.showCaptcha) {
// clickCaptcha(form.uuid, (captchaInfo: string) => onSubmit(captchaInfo))
// } else {
onSubmit()
// }
}
})
}
const load = () => {
getCaptchaData().then((res) => {
form.uuid = res.data.uuid
state.captcha = 'data:image\/png;base64,' + res.data.img
})
}
const onSubmit = (captchaInfo = '') => {
state.submitLoading = true
form.captchaInfo = captchaInfo
let publicKey = `-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDUCvEWRhSSdqchyq8bAV49Xpx8
XYjeBzUnzTZm3FVQeFKlf3TGlNc2Uw7anVFsqU2bXBZMOhQlrFZxnLhcssD3n/LZ
6CSptRIFg3YPi0sRwL06yov+x16DjcR4iyrQai7zzIVSS2iggy0D7bnJ5Jq8OoVs
nbTuGGTWeRWbZ7b/yQIDAQAB
-----END PUBLIC KEY-----`
const encrypt = new JSEncrypt()
encrypt.setPublicKey(publicKey)
const encrypted = encrypt.encrypt(form.password)
form.password = encrypted as string
login('post', form)
login(form)
.then((res) => {
adminInfo.dataFill({
id: res.data.accountId,
username: '',
nickname: '',
id: res.data.sysUser.id,
username: res.data.sysUser.account,
nickname: res.data.sysUser.userName,
avatar: '',
last_login_time: '',
token: res.data.token,
@ -187,6 +204,7 @@ nbTuGGTWeRWbZ7b/yQIDAQAB
})
.finally(() => {
state.submitLoading = false
load()
})
}
</script>