实现统一门户登录跳转免登录

统一门户所有应用页面,点击跳转对应业务系统,实现业务系统免登录

TypeScript 复制代码
//获取所有业务系统项(获取并存储到仓库)
//用于页面展示
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)
  }
}

业务系统接收处理页面

  1. 新建 UILLogin 页面(@/views/Login/UILLogin.vue),作为接收并处理 Ticket 的转换页面
  • 根据项目 Code 获取对应的 applicationId(用于菜单获取)。
  • 接收统一门户跳转时传递的参数:appCode、ticket、uilBackendUrl 和 grantId,存入 uilLogindata 对象。
  • 调用业务系统提供的 Token 换取接口(uilLogin),传入 uilLogindata。若接口调用成功,则执行与常规登录相同的后续流程(如获取用户信息、权限菜单等并存储);若失败,则拦截并跳转至登录页。
  • 若统一门户跳转时指定了目标模块(redirect 参数),则登录成功后跳转至该模块;否则跳转至菜单首项。
TypeScript 复制代码
<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 页面,确保该页面可被访问。
TypeScript 复制代码
 {
    path: '/uil-login',
    component: () => import('@/views/Login/UILLogin.vue'),
    name: 'uilLogin',
    meta: {
      hidden: true,
      title: 'UIL登录',
      noTagsView: true
    }
  },
  • 将 /uil-login 加入免重定向白名单(NO_REDIRECT_WHITE_LIST),避免在该页面触发登录重定向逻辑。
TypeScript 复制代码
export const NO_REDIRECT_WHITE_LIST = ['/login', '/uis-login', '/uploadPage', '/uil-login']

在 @/api/login.ts 中新增 uilLogin 后端 Token 换取接口。

TypeScript 复制代码
// uil免登录
export const uilLogin = (data): Promise<IResponse> => {
  return request.post({ url: `/uil/login`, data })
}
相关推荐
爱分享的鱼鱼7 小时前
对比理解 Vue 响应式 API:data(), ref、reactive、computed 与 watch 详解
前端·vue.js
JS_GGbond7 小时前
【性能优化】给Vue应用“瘦身”:让你的网页快如闪电的烹饪秘籍
前端·vue.js
cat三三7 小时前
java之异常
java·开发语言
T___T7 小时前
一个定时器,理清 JavaScript 里的 this
前端·javascript·面试
奇树谦7 小时前
【Qt实战】实现图片缩放、平移与像素级查看功能
开发语言·qt
代码小学僧7 小时前
从 Arco Table 迁移到 VTable:VTable使用经验分享
前端·react.js·开源
微笑的曙光7 小时前
Vue3 环境搭建 5 步走(零基础友好)
前端
不知名用户来了7 小时前
基于vue3 封装的antdv/element-Plus 快速生成增删改查页面
前端
我命由我123457 小时前
Python Flask 开发问题:ImportError: cannot import name ‘Markup‘ from ‘flask‘
开发语言·后端·python·学习·flask·学习方法·python3.11
wjs20247 小时前
Go 语言指针
开发语言