登录流程
This commit is contained in:
parent
7ab97a1377
commit
e66a9523b2
@ -5,7 +5,7 @@ ENV = 'development'
|
|||||||
VITE_BASE_PATH = './'
|
VITE_BASE_PATH = './'
|
||||||
|
|
||||||
# 代理配置(开发使用),必须在一行中
|
# 代理配置(开发使用),必须在一行中
|
||||||
VITE_APP_PROXY=[["/api","https://usp2.jsspisoft.com/api"]]
|
VITE_APP_PROXY=[["/api","http://192.168.130.12:8080/api"]]
|
||||||
|
|
||||||
# 开发环境下跨域代理,请输入要跨域的api地址 - 尾部无需带'/'
|
# 开发环境下跨域代理,请输入要跨域的api地址 - 尾部无需带'/'
|
||||||
# VITE_PROXY_URL = 'http://localhost:8000'
|
# VITE_PROXY_URL = 'http://localhost:8000'
|
||||||
|
@ -19,7 +19,6 @@
|
|||||||
"element-plus": "2.7.4",
|
"element-plus": "2.7.4",
|
||||||
"esno": "4.7.0",
|
"esno": "4.7.0",
|
||||||
"font-awesome": "4.7.0",
|
"font-awesome": "4.7.0",
|
||||||
"jsencrypt": "^3.3.2",
|
|
||||||
"lodash-es": "4.17.21",
|
"lodash-es": "4.17.21",
|
||||||
"mitt": "3.0.1",
|
"mitt": "3.0.1",
|
||||||
"nprogress": "0.2.0",
|
"nprogress": "0.2.0",
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import createAxios from '/@/utils/axios'
|
import createAxios from '/@/utils/axios'
|
||||||
import { useAdminInfo } from '/@/stores/adminInfo'
|
|
||||||
|
|
||||||
export function index() {
|
export function index() {
|
||||||
return createAxios({
|
return createAxios({
|
||||||
@ -15,18 +14,17 @@ export function userinfo() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function login(method: 'get' | 'post', params: object = {}) {
|
export function login(params: object = {}) {
|
||||||
return createAxios({
|
return createAxios({
|
||||||
url: '/api/auth/token/invoke',
|
url: '/api/auth/login',
|
||||||
data: params,
|
data: params,
|
||||||
method: method,
|
method: 'POST',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function logout() {
|
export function logout() {
|
||||||
// const adminInfo = useAdminInfo()
|
|
||||||
return createAxios({
|
return createAxios({
|
||||||
url: '/api/auth/token/revoke',
|
url: '/api/auth/logout',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -27,8 +27,8 @@ export const changeTerminalConfigUrl = '/admin/ajax/changeTerminalConfig'
|
|||||||
export const clearCacheUrl = '/admin/ajax/clearCache'
|
export const clearCacheUrl = '/admin/ajax/clearCache'
|
||||||
|
|
||||||
// 公共
|
// 公共
|
||||||
export const captchaUrl = '/api/common/captcha'
|
export const captchaUrl = '/api/captchaImage'
|
||||||
export const clickCaptchaUrl = '/api/common/clickCaptcha'
|
export const clickCaptchaUrl = '/api/captchaImage'
|
||||||
export const checkClickCaptchaUrl = '/api/common/checkClickCaptcha'
|
export const checkClickCaptchaUrl = '/api/common/checkClickCaptcha'
|
||||||
export const refreshTokenUrl = '/api/common/refreshToken'
|
export const refreshTokenUrl = '/api/common/refreshToken'
|
||||||
|
|
||||||
@ -218,13 +218,10 @@ export function buildCaptchaUrl() {
|
|||||||
return getUrl() + captchaUrl + '?server=1'
|
return getUrl() + captchaUrl + '?server=1'
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getCaptchaData(id: string) {
|
export function getCaptchaData() {
|
||||||
return createAxios({
|
return createAxios({
|
||||||
url: clickCaptchaUrl,
|
url: clickCaptchaUrl,
|
||||||
method: 'get',
|
method: 'post',
|
||||||
params: {
|
|
||||||
id,
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,11 +87,11 @@ const state: {
|
|||||||
|
|
||||||
const load = () => {
|
const load = () => {
|
||||||
state.loading = true
|
state.loading = true
|
||||||
getCaptchaData(props.uuid).then((res) => {
|
getCaptchaData().then((res) => {
|
||||||
state.xy = []
|
state.xy = []
|
||||||
state.tip = ''
|
state.tip = ''
|
||||||
state.loading = false
|
state.loading = false
|
||||||
state.captcha = res.data
|
state.captcha.base64 = 'data:image\/png;base64,' + res.data.img
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
export default {
|
export default {
|
||||||
'Please enter an account': '请输入账号',
|
'Please enter an account': '请输入账号',
|
||||||
'Please input a password': '请输入密码',
|
'Please input a password': '请输入密码',
|
||||||
|
'Please input a captcha': '请输入验证码',
|
||||||
'Hold session': '保持会话',
|
'Hold session': '保持会话',
|
||||||
'Sign in': '登录',
|
'Sign in': '登录',
|
||||||
}
|
}
|
||||||
|
@ -160,7 +160,6 @@ const onAdminInfo = () => {
|
|||||||
|
|
||||||
const onLogout = () => {
|
const onLogout = () => {
|
||||||
logout().then(() => {
|
logout().then(() => {
|
||||||
debugger
|
|
||||||
Local.remove(ADMIN_INFO)
|
Local.remove(ADMIN_INFO)
|
||||||
router.go(0)
|
router.go(0)
|
||||||
})
|
})
|
||||||
|
@ -1407,35 +1407,35 @@ const init = () => {
|
|||||||
/**
|
/**
|
||||||
* 后台初始化请求,获取站点配置,动态路由等信息
|
* 后台初始化请求,获取站点配置,动态路由等信息
|
||||||
*/
|
*/
|
||||||
index().then((res) => {
|
// index().then((res) => {
|
||||||
// siteConfig.dataFill(res.data.siteConfig)
|
// siteConfig.dataFill(res.data.siteConfig)
|
||||||
// terminal.changePort(res.data.terminal.installServicePort)
|
// terminal.changePort(res.data.terminal.installServicePort)
|
||||||
// terminal.changePackageManager(res.data.terminal.npmPackageManager)
|
// terminal.changePackageManager(res.data.terminal.npmPackageManager)
|
||||||
// siteConfig.setInitialize(true)
|
// siteConfig.setInitialize(true)
|
||||||
|
|
||||||
// if (!isEmpty(res.data.adminInfo)) {
|
// if (!isEmpty(res.data.adminInfo)) {
|
||||||
// adminInfo.dataFill(res.data.adminInfo)
|
// adminInfo.dataFill(res.data.adminInfo)
|
||||||
// siteConfig.setUserInitialize(true)
|
// siteConfig.setUserInitialize(true)
|
||||||
// }
|
// }
|
||||||
|
|
||||||
if (res.data) {
|
// if (res.data) {
|
||||||
handleAdminRoute(menu)
|
handleAdminRoute(menu)
|
||||||
|
|
||||||
// 预跳转到上次路径
|
// 预跳转到上次路径
|
||||||
if (route.params.to) {
|
if (route.params.to) {
|
||||||
const lastRoute = JSON.parse(route.params.to as string)
|
const lastRoute = JSON.parse(route.params.to as string)
|
||||||
if (lastRoute.path != adminBaseRoutePath) {
|
if (lastRoute.path != adminBaseRoutePath) {
|
||||||
let query = !isEmpty(lastRoute.query) ? lastRoute.query : {}
|
let query = !isEmpty(lastRoute.query) ? lastRoute.query : {}
|
||||||
routePush({ path: lastRoute.path, query: query })
|
routePush({ path: lastRoute.path, query: query })
|
||||||
return
|
return
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 跳转到第一个菜单
|
|
||||||
let firstRoute = getFirstRoute(navTabs.state.tabsViewRoutes)
|
|
||||||
if (firstRoute) routePush(firstRoute.path)
|
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|
||||||
|
// 跳转到第一个菜单
|
||||||
|
let firstRoute = getFirstRoute(navTabs.state.tabsViewRoutes)
|
||||||
|
if (firstRoute) routePush(firstRoute.path)
|
||||||
|
// }
|
||||||
|
// })
|
||||||
}
|
}
|
||||||
|
|
||||||
const onAdaptiveLayout = () => {
|
const onAdaptiveLayout = () => {
|
||||||
|
@ -90,10 +90,14 @@ function createAxios<Data = any, T = ApiPromise<Data>>(axiosConfig: AxiosRequest
|
|||||||
|
|
||||||
if (config.method === 'post' && config.data) {
|
if (config.method === 'post' && config.data) {
|
||||||
// 对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) {
|
} else if (config.method === 'get' && config.params) {
|
||||||
// 对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
|
// 自动携带token
|
||||||
|
@ -1,35 +1,38 @@
|
|||||||
import CryptoJS from 'crypto-js'
|
import CryptoJS from 'crypto-js'
|
||||||
|
|
||||||
const key = ''
|
const key = 'b6967ee87b86d85a'
|
||||||
|
|
||||||
export function encrypt_aes(plaintText: string, iv: string) {
|
export function encrypt_aes(text: any, iv: string) {
|
||||||
const encryptedData = CryptoJS.AES.encrypt(plaintText, key, {
|
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,
|
iv,
|
||||||
|
|
||||||
mode: CryptoJS.mode.CBC,
|
mode: CryptoJS.mode.CBC,
|
||||||
|
padding: CryptoJS.pad.ZeroPadding,
|
||||||
padding: CryptoJS.pad.Pkcs7,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// const encryptedBase64Str = encryptedData.toString()
|
|
||||||
|
|
||||||
// // 需要读取encryptedData上的ciphertext.toString()才能拿到跟Java一样的密文
|
// // 需要读取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) {
|
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,
|
iv,
|
||||||
mode: CryptoJS.mode.CBC,
|
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) {
|
export function generateRandomNumber(length: number) {
|
||||||
|
@ -50,7 +50,23 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-input>
|
</el-input>
|
||||||
</el-form-item>
|
</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-form-item>
|
||||||
<el-button
|
<el-button
|
||||||
:loading="state.submitLoading"
|
:loading="state.submitLoading"
|
||||||
@ -73,6 +89,7 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { onMounted, onBeforeUnmount, reactive, ref, nextTick } from 'vue'
|
import { onMounted, onBeforeUnmount, reactive, ref, nextTick } from 'vue'
|
||||||
|
import { getCaptchaData } from '/@/api/common'
|
||||||
import * as pageBubble from '/@/utils/pageBubble'
|
import * as pageBubble from '/@/utils/pageBubble'
|
||||||
import type { FormInstance, InputInstance } from 'element-plus'
|
import type { FormInstance, InputInstance } from 'element-plus'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
@ -80,10 +97,9 @@ import { editDefaultLang } from '/@/lang/index'
|
|||||||
import { useConfig } from '/@/stores/config'
|
import { useConfig } from '/@/stores/config'
|
||||||
import { useAdminInfo } from '/@/stores/adminInfo'
|
import { useAdminInfo } from '/@/stores/adminInfo'
|
||||||
import { login } from '/@/api/backend'
|
import { login } from '/@/api/backend'
|
||||||
import { uuid } from '/@/utils/random'
|
|
||||||
import { buildValidatorData } from '/@/utils/validate'
|
import { buildValidatorData } from '/@/utils/validate'
|
||||||
import router from '/@/router'
|
import router from '/@/router'
|
||||||
import clickCaptcha from '/@/components/clickCaptcha'
|
// import clickCaptcha from '/@/components/clickCaptcha'
|
||||||
import toggleDark from '/@/utils/useDark'
|
import toggleDark from '/@/utils/useDark'
|
||||||
import { fullUrl } from '/@/utils/common'
|
import { fullUrl } from '/@/utils/common'
|
||||||
import { adminBaseRoutePath } from '/@/router/static/adminBase'
|
import { adminBaseRoutePath } from '/@/router/static/adminBase'
|
||||||
@ -97,16 +113,18 @@ toggleDark(config.layout.isDark)
|
|||||||
const formRef = ref<FormInstance>()
|
const formRef = ref<FormInstance>()
|
||||||
const usernameRef = ref<InputInstance>()
|
const usernameRef = ref<InputInstance>()
|
||||||
const passwordRef = ref<InputInstance>()
|
const passwordRef = ref<InputInstance>()
|
||||||
|
const captchaRef = ref<InputInstance>()
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
showCaptcha: false,
|
showCaptcha: true,
|
||||||
submitLoading: false,
|
submitLoading: false,
|
||||||
|
captcha: '',
|
||||||
})
|
})
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
username: '',
|
username: '',
|
||||||
password: '',
|
password: '',
|
||||||
keep: false,
|
keep: false,
|
||||||
captchaId: uuid(),
|
uuid: '',
|
||||||
captchaInfo: '',
|
code: '',
|
||||||
})
|
})
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
@ -115,6 +133,7 @@ const { t } = useI18n()
|
|||||||
const rules = reactive({
|
const rules = reactive({
|
||||||
username: [buildValidatorData({ name: 'required', message: t('login.Please enter an account') }), buildValidatorData({ name: 'account' })],
|
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' })],
|
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 = () => {
|
const focusInput = () => {
|
||||||
@ -122,6 +141,8 @@ const focusInput = () => {
|
|||||||
usernameRef.value!.focus()
|
usernameRef.value!.focus()
|
||||||
} else if (form.password === '') {
|
} else if (form.password === '') {
|
||||||
passwordRef.value!.focus()
|
passwordRef.value!.focus()
|
||||||
|
} else if (form.code === '') {
|
||||||
|
captchaRef.value!.focus()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,7 +150,7 @@ onMounted(() => {
|
|||||||
timer = window.setTimeout(() => {
|
timer = window.setTimeout(() => {
|
||||||
pageBubble.init()
|
pageBubble.init()
|
||||||
}, 1000)
|
}, 1000)
|
||||||
|
load()
|
||||||
// login('get')
|
// login('get')
|
||||||
// .then((res) => {
|
// .then((res) => {
|
||||||
// state.showCaptcha = res.data.captcha
|
// state.showCaptcha = res.data.captcha
|
||||||
@ -148,34 +169,30 @@ onBeforeUnmount(() => {
|
|||||||
const onSubmitPre = () => {
|
const onSubmitPre = () => {
|
||||||
formRef.value?.validate((valid) => {
|
formRef.value?.validate((valid) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
if (state.showCaptcha) {
|
// if (state.showCaptcha) {
|
||||||
clickCaptcha(form.captchaId, (captchaInfo: string) => onSubmit(captchaInfo))
|
// clickCaptcha(form.uuid, (captchaInfo: string) => onSubmit(captchaInfo))
|
||||||
} else {
|
// } else {
|
||||||
onSubmit()
|
onSubmit()
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const load = () => {
|
||||||
|
getCaptchaData().then((res) => {
|
||||||
|
form.uuid = res.data.uuid
|
||||||
|
state.captcha = 'data:image\/png;base64,' + res.data.img
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const onSubmit = (captchaInfo = '') => {
|
const onSubmit = (captchaInfo = '') => {
|
||||||
state.submitLoading = true
|
state.submitLoading = true
|
||||||
form.captchaInfo = captchaInfo
|
login(form)
|
||||||
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)
|
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
adminInfo.dataFill({
|
adminInfo.dataFill({
|
||||||
id: res.data.accountId,
|
id: res.data.sysUser.id,
|
||||||
username: '',
|
username: res.data.sysUser.account,
|
||||||
nickname: '',
|
nickname: res.data.sysUser.userName,
|
||||||
avatar: '',
|
avatar: '',
|
||||||
last_login_time: '',
|
last_login_time: '',
|
||||||
token: res.data.token,
|
token: res.data.token,
|
||||||
@ -187,6 +204,7 @@ nbTuGGTWeRWbZ7b/yQIDAQAB
|
|||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
state.submitLoading = false
|
state.submitLoading = false
|
||||||
|
load()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
Loading…
Reference in New Issue
Block a user