ruoyi-vue-pro数据大屏——纯前端单点登录
ruoyi-vue-pro 的已经集成了数据大屏模块go-view,并且用vue开发了前端,可以进行拖来拽就能实现一个精美的数据大屏应用,然而点击【报表管理->大屏设计】你却发现需要输入账号密码登陆,这多少有点遗憾。

ruoyi-vue-pro已经支持应用注册并进行oauth2的授权功能,然而最后一公里我们必须自己去走。
1、在【三方授权->应用管理】中注册数据大屏应用report

2、改造yudao-ui-go-view-master项目支持断点登陆
A)新增callback组件。
新增页面src/views/sso/callback.vue,内容如下:
<template> <!-- 登录 --> <div> </div> </template> <script lang="ts" setup> import { reactive, ref, onMounted } from 'vue' import { Router, useRoute } from 'vue-router'; import { ssoLoginCallbackApi } from '@/api/path' import { useSystemStore } from '@/store/modules/systemStore/systemStore' import { SystemStoreUserInfoEnum, SystemStoreEnum } from '@/store/modules/systemStore/systemStore.d' import { StorageEnum } from '@/enums/storageEnum'; import { PageEnum, PreviewEnum } from '@/enums/pageEnum' import { routerTurnByName } from '@/utils' import {getTenantIdByNameApi, getUserInfoApi, loginApi} from '@/api/path' const systemStore = useSystemStore() const t = window['$t'] onMounted(async () => { const route = useRoute(); const code = route.query.code; if(!code) { return; } var loginRes = await ssoLoginCallbackApi(code.toString()); if(loginRes && loginRes.data) { // ① Token 信息(先存储下,保证可以加载个人信息) const tokenValue = loginRes.data.access_token const tokenName = 'Authorization' systemStore.setItem(SystemStoreEnum.TENANT_INFO, { tenantId: 1 }) systemStore.setItem(SystemStoreEnum.USER_INFO, { [SystemStoreUserInfoEnum.USER_TOKEN]: tokenValue, [SystemStoreUserInfoEnum.TOKEN_NAME]: tokenName }) // 个人信息 const profileRes = await getUserInfoApi(); const id = profileRes?.data?.id; const username = profileRes?.data?.username; const nickname = profileRes?.data?.nickname; if(id && username && nickname){ // 存储到 pinia systemStore.setItem(SystemStoreEnum.USER_INFO, { [SystemStoreUserInfoEnum.USER_TOKEN]: tokenValue, [SystemStoreUserInfoEnum.TOKEN_NAME]: tokenName, [SystemStoreUserInfoEnum.USER_ID]: id, [SystemStoreUserInfoEnum.USER_NAME]: username, [SystemStoreUserInfoEnum.NICK_NAME]: nickname, }) window['$message'].success(t('login.login_success')) var sso_url = localStorage.getItem(StorageEnum.GO_SSO_URL); console.log("sso_url:"+sso_url) if(sso_url) { localStorage.removeItem(StorageEnum.GO_SSO_URL); window.location.href = sso_url; return; } routerTurnByName(sso_url || PageEnum.BASE_HOME_NAME, true) return; } window['$message'].error('登陆失败:'+profileRes.msg) routerTurnByName(PageEnum.ERROR_PAGE_NAME_403, true) } else { window['$message'].success(loginRes.msg); window['$message'].error('登陆失败:'+loginRes.msg) routerTurnByName(PageEnum.BASE_LOGIN_NAME, true) } }) </script> B)新增callback路由
在src\router\base.ts中找到LoginRoute,在后面新增代码:
export const SsoCallbackRoute: RouteRecordRaw = { path: PageEnum.SSO_CALL_BACK, name: PageEnum.SSO_CALL_BACK_NAME, component: () => import('@/views/sso/callback.vue'), meta: { title: '单点登录', }, };在src\router\index.ts文件中导入

C)新增单点登陆api。
我这里数据大屏的是内网,而且后端使用的是ruoyi-vue-pro,所有appKey, appSecret都是写死在js中的,后期根据需要进行改造配置到后端application.yaml中。

在src\api\path\system.api.ts中,找到logoutApi,在其后新增单点登陆api如下:
// * SSO登录 // 可以改写成,你的 clientId const clientId = 'yudao-sso-demo-by-code'; export const ssoLogin = () => { const redirectUri = encodeURIComponent('http://localhost:3000/callback'); // 注意,需要使用 encodeURIComponent 编码地址 const responseType = 'code'; // 1)授权码模式,对应 code;2)简化模式,对应 token window.location.href = 'https://192.168.1.222:80/sso?client_id=' + clientId + '&redirect_uri=' + redirectUri + '&response_type=' + responseType; } // * SSO登录 export const ssoLoginCallbackApi = async (code: String) => { try { const redirectUri = "http://localhost:3000/callback"; const url = "https://192.168.1.222:80/admin-api/system/oauth2/token?grant_type=authorization_code&code="+ code+"&redirect_uri="+redirectUri; const params = { } const headers = { "Content-Type": ContentTypeEnum.JSON, "tenant-id": "1", "Authorization": "Basic " + encode(new TextEncoder().encode(clientId+":datav123")) }; const config = { baseURL:'', headers: headers }; var res = await axios.post(url, params, config) console.log(res) return res.data } catch (err) { httpErrorHandle() } } // 单点登陆callback中调用,查询用户个人信息 export const getUserInfoApi = async () => { try { const res = await http(RequestHttpEnum.GET)<ProfileVO>(`${ModuleTypeEnum.SYSTEM}/oauth2/user/get`) return res } catch (err) { httpErrorHandle() } } D) 在路由守卫中拦截sso
在src\router\router-guards.ts文件中判断白名单前,新增代码如下:
if(to && to.query && to.query.sso == 'true'){ localStorage.setItem(StorageEnum.GO_SSO_URL, window.location.href) // @ts-ignore if (!routerAllowList.includes(to.name) && !loginCheck()) { ssoLogin(); return; } }E)处理后端返回未认证(状态码为401)
在src\api\axios.ts中新增代码,如果sso访问但未登陆成功或者token超时则发起单点登陆,代码如下:

3、改造yudao-vue-pro中的【报表管理->大屏设计】中的页面

只需要在url上加一个参数sso=true就行了只需要在url上加一个参数sso=true就行了只需要在url上加一个参数sso=true就行了
4、验证访问数据大屏
A)验证单点登录
重新启动yudao-vue-pro,yudao-ui-go-view,或刷新【报表管理->大屏设计】,将会出现授权请求页面如下:

这个页面是yudao-vue-pro中的src\views\sso.vue,这里我只是改了下样式,这个页面应该不需要改动。同意授权后页面会自动跳转到数据大屏的首页,如下图:

授权一次以后就可以愉快的访问了授权一次以后就可以愉快的访问了授权一次以后就可以愉快的访问了
B)验证在yudao-vue-pro中配置菜单直接访问数据看板

============= 相关博文 ============
ruoyi-vue-pro数据大屏——路由支持history,告别难看的hash路由
ruoyi-vue-pro数据大屏——单点登录,告别手输密码(适用于不带后端服务的情况)
ruoyi-vue-pro优化——如何将一个模块快速变成一个独立的应用进行开发,部署,管理
ruoyi-vue-pro增强——新增通用单点登录模块yudao-module-sso(下载链接在博文末尾)
ruoyi-vue-pro数据大屏优化——在yudao-module-report-app使用yudao-moudle-sso优化单点登录
ruoyi-vue-pro优化——让菜单支持多个参数,一键直达【经营分析】、【生产报表】、【销售报表】
ruoyi-vue-pro优化——模块单独打包,增量更新、部署,告别打包等待,上传等待,节省网络流量
============= 相关博文 ============