diff --git a/src/components.d.ts b/src/components.d.ts index 8892e08..300a5b0 100644 --- a/src/components.d.ts +++ b/src/components.d.ts @@ -31,9 +31,13 @@ declare module '@vue/runtime-core' { ElScrollbar: typeof import('element-plus/es')['ElScrollbar'] ElSubMenu: typeof import('element-plus/es')['ElSubMenu'] ElSwitch: typeof import('element-plus/es')['ElSwitch'] + ElTab: typeof import('element-plus/es')['ElTab'] + ElTabPane: typeof import('element-plus/es')['ElTabPane'] + ElTabs: typeof import('element-plus/es')['ElTabs'] ElTooltip: typeof import('element-plus/es')['ElTooltip'] Empty: typeof import('./components/empty/Empty.vue')['default'] IconEpArrowDown: typeof import('~icons/ep/arrow-down')['default'] + IconEpArrowLeft: typeof import('~icons/ep/arrow-left')['default'] IconEpArrowRight: typeof import('~icons/ep/arrow-right')['default'] IconEpArrowRightBold: typeof import('~icons/ep/arrow-right-bold')['default'] IconEpBell: typeof import('~icons/ep/bell')['default'] @@ -43,6 +47,7 @@ declare module '@vue/runtime-core' { IconEpLock: typeof import('~icons/ep/lock')['default'] IconEpMonitor: typeof import('~icons/ep/monitor')['default'] IconEpPosition: typeof import('~icons/ep/position')['default'] + IconEpRight: typeof import('~icons/ep/right')['default'] IconEpService: typeof import('~icons/ep/service')['default'] IconEpSwitchButton: typeof import('~icons/ep/switch-button')['default'] IconEpUploadFilled: typeof import('~icons/ep/upload-filled')['default'] diff --git a/src/config.ts b/src/config.ts index d6aa3f9..82b723e 100644 --- a/src/config.ts +++ b/src/config.ts @@ -11,6 +11,10 @@ export const enableUserStorage = false export const userKey = 'cmcUserData' // 本地存储的cookie kye值 export const tokenKey = 'CMC_TOKEN' +// 本地存储的天融信cookie kye值 +export const trxTokenKey = 'TRX_TOKEN' +// 本地存储的 ukeypassword kye值 +export const ukeyPasswordKey = 'UKEY_PASSWORD' // 最大缓存组件实例数 export const cacheViewMax = 15 export const formSetting = { diff --git a/src/layouts/components/personal/index.vue b/src/layouts/components/personal/index.vue index 7d335d2..ec708a7 100644 --- a/src/layouts/components/personal/index.vue +++ b/src/layouts/components/personal/index.vue @@ -123,10 +123,10 @@ export default defineComponent({ ElMessageBox.confirm('您确定要退出该系统吗?', '提示', { type: 'warning' }).then(async () => { - const res = await logout() - if (res.success) { - store.dispatch('permission/ResetRoutes') - } + // 调用 ResetRoutes -> ukey/Logout 通知天融信退出 + await store.dispatch('permission/ResetRoutes') + // 云管退出 + await logout() }) } // 个人信息 diff --git a/src/layouts/components/personal/useTokenAndLock.ts b/src/layouts/components/personal/useTokenAndLock.ts index 481379a..6ec0998 100644 --- a/src/layouts/components/personal/useTokenAndLock.ts +++ b/src/layouts/components/personal/useTokenAndLock.ts @@ -1,6 +1,9 @@ import { computed, onMounted, onUnmounted } from 'vue' import { useStore } from 'vuex' import { useRouter, useRoute } from 'vue-router' +import { getClientHello } from 'services/ukeyAuth.js' +import { replaceToken } from 'services' +import { getToken, getUkeyPassword } from 'utils/auth' export default function () { const store = useStore() @@ -16,6 +19,15 @@ export default function () { } } init() + // 获取最新token + async function getLastToken() { + const token = getToken() + const res = await replaceToken({ token }) + if (!res.success) { + clearTimer() + store.dispatch('permission/ResetRoutes') + } + } const operateTime = computed(() => store.state.app.operateTime) const lockScreenTime = computed(() => store.getters.systemConfig.lockScreenTime) @@ -26,12 +38,21 @@ export default function () { } onMounted(() => { timer = setInterval(() => { + getLastToken() // 锁屏 const interval = 1000 * 60 * Number(lockScreenTime.value) // checkUserStatus() if (interval && new Date().getTime() - operateTime.value >= interval) { lockScreen() } + // 每 20s 在线检测 ueky 是否存在 + if (getUkeyPassword()) { + getClientHello(getUkeyPassword()).then((checkRes: any) => { + if (checkRes.result !== 0) { + store.dispatch('permission/ResetRoutes') + } + }) + } }, 1000 * 20) }) onUnmounted(clearTimer) diff --git a/src/services/index.js b/src/services/index.js index 51a33f2..3c342ba 100644 --- a/src/services/index.js +++ b/src/services/index.js @@ -51,6 +51,9 @@ export function getServiceQuota(tenantId, data) { params: wrapperParams(data) }) } +export function replaceToken(params) { + return request.get('/sms/v1/token', { params }) +} // 获取用户权限 export function getUserPermissions() { return request.get('/sms/v1/users/permissions') diff --git a/src/services/trxLogin.js b/src/services/trxLogin.js new file mode 100644 index 0000000..4105d2c --- /dev/null +++ b/src/services/trxLogin.js @@ -0,0 +1,39 @@ +import request from 'utils/request' + +export function getLoginRandom(ngxCookie) { + return request.get( + '/sms/v1/trx/getRandomStr', + {}, + { + headers: { + ngxCookie + } + } + ) +} + +export function trxLogin(params) { + return request.post('/sms/v1/trx/login', params) +} + +export function offlineToken() { + return request.post('/sms/v1/trx/logout') +} + +// 理想那边给的代码调用 getAuthToken 时需要传 ip,云管目前不传 +export function getIp() { + return request({ + url: '/sso/getIp', + headers: { + isToken: false + }, + method: 'get' + }) +} + +export function queryAppList() { + return request({ + url: '/queryAppList', + method: 'get' + }) +} diff --git a/src/services/ukeyAuth.js b/src/services/ukeyAuth.js new file mode 100644 index 0000000..32592e8 --- /dev/null +++ b/src/services/ukeyAuth.js @@ -0,0 +1,74 @@ +import axios from 'axios' +import { ElMessage } from 'element-plus' + +axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8' +// 创建axios实例 +const webssoService = axios.create({ + // axios中请求配置有baseURL选项,表示请求URL公共部分 + baseURL: '', + // 超时 + timeout: 30000 +}) +// request拦截器 +webssoService.interceptors.request.use( + config => { + // get请求映射params参数 + if (config.method === 'get' && config.params) { + let url = config.url + '?' + for (const propName of Object.keys(config.params)) { + const value = config.params[propName] + var part = encodeURIComponent(propName) + '=' + if (value !== null && typeof value !== 'undefined') { + if (typeof value === 'object') { + for (const key of Object.keys(value)) { + let params = propName + '[' + key + ']' + var subPart = encodeURIComponent(params) + '=' + url += subPart + encodeURIComponent(value[key]) + '&' + } + } else { + url += part + encodeURIComponent(value) + '&' + } + } + } + url = url.slice(0, -1) + config.params = {} + config.url = url + } + return config + }, + error => { + console.log(error) + Promise.reject(error) + } +) + +// 响应拦截器 +webssoService.interceptors.response.use( + res => { + console.log('返回参数::', res) + return Promise.resolve(res.data) + }, + error => { + console.log('err::' + error) + ElMessage({ message: '无法获取用户信息,请确认代理程序是否启动', type: 'error' }) + return Promise.reject(error) + } +) + +// 获取clientHello 同步负责监测 ueky 是否拔出 +export function getClientHello(password) { + return webssoService({ + url: 'http://127.0.0.1:8899/client_hello', + method: 'post', + data: { userName: 'key', userPwd: password } + }) +} + +// 生成客户验证码 +export function getClientAuth(password, serverHello, clientHello) { + return webssoService({ + url: 'http://127.0.0.1:8899/client_auth', + method: 'post', + data: { userName: 'key', userPwd: password, serverHello, clientHello } + }) +} diff --git a/src/store/modules/permission.js b/src/store/modules/permission.js index 6c5646d..c1f89f8 100644 --- a/src/store/modules/permission.js +++ b/src/store/modules/permission.js @@ -2,7 +2,7 @@ * Created by HaijunZhang on 2018/11/12. */ import { resolvePath } from 'utils/resolvePath' -import { removeToken } from 'utils/auth' +import { removeToken, removeTrxToken } from 'utils/auth' import { getUserPermissions } from 'services' import BlankView from '@/layouts/blank.vue' import router, { resetRouter } from '@/router' @@ -130,20 +130,32 @@ const actions = { }, ResetRoutes({ commit, dispatch }, redirectToLogin = true) { return new Promise(resolve => { - resetRouter() - commit('SET_ROUTES', null) - if (enablePermissionStorage) { - localStorage.removeItem(menuKey) + const reset = () => { + resetRouter() + commit('SET_ROUTES', null) + if (enablePermissionStorage) { + localStorage.removeItem(menuKey) + } + // 重置用户信息 + commit('RESET_USER', null, { root: true }) + // 重置用户信息 + commit('SETTING_SIDE_MENU', [], { root: true }) + // 重置标签信息 + dispatch('tagsView/delAllViews', null, { root: true }) + removeToken() + removeTrxToken() + if (redirectToLogin) window.location.href = '/login' + resolve() + } + // 调用天融信单点退出系统 + if (redirectToLogin) { + dispatch('ukey/Logout', null, { root: true }).then(res => { + if (!res.success) return + reset() + }) + } else { + reset() } - // 重置用户信息 - commit('RESET_USER', null, { root: true }) - // 重置用户信息 - commit('SETTING_SIDE_MENU', [], { root: true }) - // 重置标签信息 - dispatch('tagsView/delAllViews', null, { root: true }) - removeToken() - if (redirectToLogin) window.location.href = '/login' - resolve() }) } } diff --git a/src/store/modules/ukey.js b/src/store/modules/ukey.js new file mode 100644 index 0000000..d5f5df7 --- /dev/null +++ b/src/store/modules/ukey.js @@ -0,0 +1,87 @@ +import { getClientHello, getClientAuth } from 'services/ukeyAuth.js' +import { getLoginRandom, trxLogin, offlineToken } from 'services/trxLogin.js' +import Cookies from 'js-cookie' +import { ElMessage } from 'element-plus' +const state = {} +const mutations = {} +const actions = { + // 登录 + Login({ commit }, password) { + return new Promise((resolve, reject) => { + // 调用 ukey 获取 clientHello + getClientHello(password).then( + checkRes => { + if (checkRes.result !== 0) { + Cookies.remove('ngx_cookie') + ElMessage({ message: checkRes.message, type: 'error' }) + return Promise.reject(new Error(checkRes.message)) + } + const clientHello = checkRes.clientHello + Cookies.set('ngx_cookie', clientHello) + // 调用天融信单点登录获取 serverHello + getLoginRandom(clientHello).then( + randomRes => { + if (!randomRes.success) { + ElMessage({ message: randomRes.message, type: 'error' }) + return Promise.reject(new Error(randomRes.message)) + } + let serverHello = randomRes.data + // 调用 ukey 获取 ClientAuth + getClientAuth(password, serverHello, clientHello).then( + authRes => { + // 暂未用到 + const ClientAuth = authRes.clientAuth + trxLogin({ + clientHello, + serverHello + }).then( + tokenRes => { + if (!tokenRes.success) { + ElMessage({ message: tokenRes.message, type: 'error' }) + return Promise.reject(new Error(tokenRes.message)) + } + resolve(tokenRes) + }, + err => { + reject(err) + } + ) + }, + err => { + reject(err) + } + ) + }, + err => { + reject(err) + } + ) + }, + err => { + reject(err) + } + ) + }) + }, + // 退出系统 + Logout() { + return new Promise((resolve, reject) => { + // 调用天融信单点退出系统 + offlineToken().then( + res => { + console.log('调用天融信单点退出系统', res) + resolve(res) + }, + err => { + reject(err) + } + ) + }) + } +} +export default { + namespaced: true, + state, + mutations, + actions +} diff --git a/src/utils/auth.ts b/src/utils/auth.ts index 8fedc83..bda2328 100644 --- a/src/utils/auth.ts +++ b/src/utils/auth.ts @@ -1,7 +1,8 @@ /** * Created by HaijunZhang on 2018/11/16. */ -import { tokenKey } from '@/config' +import { encrypt, decrypt } from 'utils/crypto' +import { tokenKey, trxTokenKey, ukeyPasswordKey } from '@/config' export function getToken() { return sessionStorage.getItem(tokenKey) @@ -14,3 +15,24 @@ export function setToken(token: string) { export function removeToken() { return sessionStorage.removeItem(tokenKey) } + +export function getTrxToken() { + return sessionStorage.getItem(trxTokenKey) +} + +export function setTrxToken(token: string) { + return sessionStorage.setItem(trxTokenKey, token) +} + +export function removeTrxToken() { + localStorage.removeItem(ukeyPasswordKey) + return sessionStorage.removeItem(trxTokenKey) +} + +export function getUkeyPassword() { + return decrypt(sessionStorage.getItem(ukeyPasswordKey)) +} +// 用于保活与监测 ukey 是否拔出 +export function setUkeyPassword(password: string) { + return localStorage.setItem(ukeyPasswordKey, encrypt(password)) +} diff --git a/src/utils/request.js b/src/utils/request.js index ace7aab..dda5ddf 100644 --- a/src/utils/request.js +++ b/src/utils/request.js @@ -55,7 +55,7 @@ const handleError = function (response) { title = data.message errorText = '' } - Notification({ + ElNotification({ type: 'error', title, message: errorText diff --git a/src/views/login/lockme.vue b/src/views/login/lockme.vue index 8d65436..93ee8e2 100644 --- a/src/views/login/lockme.vue +++ b/src/views/login/lockme.vue @@ -16,6 +16,19 @@ + + + + + + +