统一门户所有应用页面,点击跳转对应业务系统,实现业务系统免登录
//获取所有业务系统项(获取并存储到仓库)
//用于页面展示
let appSubjectVoList = ref<any>([])
appSubjectVoList.value = userStore.getAppSubjectVoList || []
//登陆后获取ticket 存储
const ticket = userStore.getTicket || ''
//当前项目编码
const PATH_URL = import.meta.env.VITE_APP_BASE_URL
//当前路由
const webclientHost = window.location.protocol + '//' + window.location.host
//token及用户信息皆为登录时获取存储到仓库
//点击业务系统图标跳转,item就是appSubjectVoList的每一项
const jumpApp = (item) => {
let data = {
appCode: item.appCode,
appName: item.appName,
parentCode: item.parentCode,
securityNetworkUrl: item.securityNetworkUrl,
securityNetworkUrlConnected: appAvailability.value[item.appCode], // 使用检测结果
schoolNetworkUrl: item.schoolNetworkUrl,
schoolNetworkUrlConnected: true,
webClientHost: webclientHost,
ticket: ticket,
token: userStore.getToken,
account: userStore.getUserInfo?.account,
appType: 0,
useType: item.useType
}
postAndRedirect(`${PATH_URL}/uil/redirect`, data)
}
//由后端重定向跳转
/**
* 以POST方式提交数据并处理接口重定向
* 接口重定向后会在新窗口打开目标页面
* @param {string} apiUrl - 后端接口地址(会重定向的接口)
* @param {object} postData - 需要传递的POST参数
*/
async function postAndRedirect(apiUrl, postData) {
try {
const response = await fetch(apiUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(postData),
redirect: 'manual'
})
if (response.status === 302) {
const redirectUrl = response.headers.get('Location')
window.open(redirectUrl, '_blank')
} else {
const data = await response.json()
if (data.data && data.code == 200) {
window.open(data.data, '_blank')
}
if (data.code == 401) {
userStore.logout()
}
}
} catch (error) {
console.error('Error:', error)
}
}
业务系统接收处理页面
- 新建 UILLogin 页面(@/views/Login/UILLogin.vue),作为接收并处理 Ticket 的转换页面
- 根据项目 Code 获取对应的 applicationId(用于菜单获取)。
- 接收统一门户跳转时传递的参数:appCode、ticket、uilBackendUrl 和 grantId,存入 uilLogindata 对象。
- 调用业务系统提供的 Token 换取接口(uilLogin),传入 uilLogindata。若接口调用成功,则执行与常规登录相同的后续流程(如获取用户信息、权限菜单等并存储);若失败,则拦截并跳转至登录页。
- 若统一门户跳转时指定了目标模块(redirect 参数),则登录成功后跳转至该模块;否则跳转至菜单首项。
<script setup lang="ts"> import { computed, reactive, ref } from 'vue' import { useRouter, useRoute } from 'vue-router' import { uilLogin } from '@/api/login' import { useAppStore } from '@/store/modules/app' import { usePermissionStore } from '@/store/modules/permission' import { useUserStore } from '@/store/modules/user' import type { RouteRecordRaw } from 'vue-router' import { userDetail, menuAccountTree } from '@/api/login' import { processMenuData } from '@/utils/tree' import { ElMessage, ElScrollbar } from 'element-plus' import { applicationInfo } from '@/api/sys/index' const { addRoute, push } = useRouter() const appStore = useAppStore() const permissionStore = usePermissionStore() const route = useRoute() const userStore = useUserStore() const redirect = ref('') let uilLogindata = reactive({ appCode: '', ticket: '', uilBackendUrl: '', grantId: '' }) if (route.query?.ticket && typeof route.query.ticket === 'string') { uilLogindata.ticket = route.query.ticket } if (route.query?.appCode && typeof route.query.appCode === 'string') { uilLogindata.appCode = route.query.appCode } if (route.query?.uilBackendUrl && typeof route.query.uilBackendUrl === 'string') { uilLogindata.uilBackendUrl = route.query.uilBackendUrl } if (route.query?.redirect && typeof route.query.redirect === 'string') { redirect.value = route.query.redirect } if (route.query?.grantId && typeof route.query.grantId === 'string') { uilLogindata.grantId = route.query.grantId } //更改为项目code~~~~~~~~~~~~~~~~~~~~~~~~~ const BASE_PATH = import.meta.env.VITE_BASE_PATH // 根据需求 获取applicationId const getapplicationId = () => { applicationInfo(BASE_PATH).then((res) => { if (res.code == 200) { appStore.setSysInfo(res.data) // ticket登录~~~~~~~~~~~~~~~~~~~~~~~~ if (uilLogindata.ticket) { uilLogin(uilLogindata) .then(async (res) => { if (res.code == 200) { userStore.setToken(res.data.tokenValue) userStore.setTokenKey(res.data.tokenName) if (appStore.getDynamicRouter) { getUser() } else { await permissionStore.generateRoutes('static').catch(() => {}) permissionStore.getAddRouters.forEach((route) => { addRoute(route as RouteRecordRaw) // 动态添加可访问路由表 }) permissionStore.setIsAddRouters(true) // 有指定页面跳转指定页面~~~~~~~~~~~~~~~~~~~~~~~~ if (redirect.value) { push(`/${redirect.value}`) } else { push({ path: permissionStore.addRouters[0].path }) } } } else { push('/login') } }) .catch(() => { push('/login') }) } else { // 没有ticket回到登录页 push('/login') } } else { ElMessage.error('网络异常,请返回重新跳转!') } }) } getapplicationId() const application = computed(() => appStore.getSysInfo) // 获取角色信息 const getUser = async () => { const resmenu = await menuAccountTree({ applicationId: application.value.id }) resmenu.data = processMenuData(resmenu.data, true, true) const res = await userDetail() res.data.menus = resmenu.data // console.log(res, 'res') if (res) { if (!res.data.menus || !res.data.menus.length) { ElMessage({ type: 'error', message: '用户没有权限' }) userStore.logout() return } userStore.setUserInfo(res.data) const routers: any[] = res.data.menus || [] // console.log(routers, 'routers') userStore.setRoleRouters(routers) appStore.getDynamicRouter && appStore.getServerDynamicRouter ? await permissionStore.generateRoutes('server', routers).catch(() => {}) : await permissionStore.generateRoutes('frontEnd', routers).catch(() => {}) console.log(permissionStore.getAddRouters, 'permissionStore.getAddRouters') permissionStore.getAddRouters.forEach((route) => { addRoute(route as RouteRecordRaw) // 动态添加可访问路由表 }) permissionStore.setIsAddRouters(true) // 有指定页面跳转指定页面~~~~~~~~~~~~~~~~~~~~~~~~ if (redirect.value) { push(`/${redirect.value}`) } else { push({ path: permissionStore.addRouters[0].path }) } } } </script> <template> <div> <ElScrollbar class="h-full"> <div class="lt-sm:p-10px dark:bg-[var(--login-bg-color)] mx-auto h-100vh flex justify-center items-center" > 跳转中... </div> </ElScrollbar> </div> </template> <style lang="less" scoped></style>
- 在路由配置(router.ts)中添加 /uil-login 页面,确保该页面可被访问。
{
path: '/uil-login',
component: () => import('@/views/Login/UILLogin.vue'),
name: 'uilLogin',
meta: {
hidden: true,
title: 'UIL登录',
noTagsView: true
}
},
- 将 /uil-login 加入免重定向白名单(NO_REDIRECT_WHITE_LIST),避免在该页面触发登录重定向逻辑。
export const NO_REDIRECT_WHITE_LIST = ['/login', '/uis-login', '/uploadPage', '/uil-login']
在 @/api/login.ts 中新增 uilLogin 后端 Token 换取接口。
// uil免登录
export const uilLogin = (data): Promise<IResponse> => {
return request.post({ url: `/uil/login`, data })
}