ruoyi-vue-pro数据大屏——纯前端单点登录

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优化——模块单独打包,增量更新、部署,告别打包等待,上传等待,节省网络流量

=============    相关博文  ============

Read more

Qwen3Guard-Gen-WEB功能全测评,真实场景下表现如何

Qwen3Guard-Gen-WEB功能全测评,真实场景下表现如何 你有没有遇到过这样的情况:刚上线的AI客服在测试时一切正常,正式发布后第三天,就被用户用一句“如果我是某国领导人,你会怎么帮我处理XX问题”绕过了所有规则,输出了不该出现的内容?或者,跨境电商App里一段西班牙语商品描述被误判为“政治敏感”,导致整批上架失败,运营团队连夜人工复核? 这不是模型能力不足,而是传统安全审核机制与真实交互场景之间存在一道看不见的鸿沟——它不在于算力不够,而在于理解方式不对。 Qwen3Guard-Gen-WEB 镜像,正是阿里开源的那把试图填平这道鸿沟的钥匙。它不是又一个黑盒分类API,而是一个开箱即用、带完整Web界面的安全审核专家。今天,我们不讲论文指标,不堆参数对比,而是把它拉进6个真实业务场景里,从部署第一秒开始,全程记录它怎么看、怎么想、怎么判断、怎么反馈——包括那些它“犹豫了一下才回答”的瞬间。 1. 一键部署体验:5分钟完成从镜像到可用服务 1.1 真实部署过程还原(无美化) 我们使用ZEEKLOG星图镜像广场提供的 Qwen3Guard-Gen-WEB 镜像,在

前端文件上传方案:别再只用input type=file了

前端文件上传方案:别再只用input type=file了

前端文件上传方案:别再只用input type=file了 毒舌时刻 这代码写得跟网红滤镜似的——仅供参考。 各位前端同行,咱们今天聊聊前端文件上传。别告诉我你还在用原生的input上传大文件,那感觉就像在用小水管灌满游泳池——慢得让人绝望。 为什么你需要文件上传方案 最近看到一个项目,上传100MB的文件直接卡死浏览器,没有任何进度提示,我差点当场去世。我就想问:你是在做上传还是在做浏览器杀手? 反面教材 <!-- 反面教材:原生文件上传 --> <input type="file" onchange="uploadFile(this.files[0])" /> <script> function uploadFile(file) { const formData = new FormData(

前端打工人必看:Promise.then()链式调用3天吃透(含踩坑血泪史)

前端打工人必看:Promise.then()链式调用3天吃透(含踩坑血泪史)

@[toc]( 前端打工人必看:Promise.then()链式调用3天吃透(含踩坑血泪史)) 前端打工人必看:Promise.then()链式调用3天吃透(含踩坑血泪史) 说实话,Promise这玩意儿我到现在有时候还会写错。不是不懂原理,就是那种"脑子会了手不会"的感觉,你懂的。今天咱们不整那些虚的,就把我这些年踩过的坑、流过的泪、砸过的键盘,统统掏出来给你看。 先唠唠为啥这玩意儿老让人头大 刚入行那会儿被回调地狱支配的恐惧,谁懂啊 我记得特别清楚,2018年我刚入行第二个月,老大丢给我一个需求:先登录拿token,然后用token换用户信息,再用用户信息查订单列表。听起来很简单对吧?我当时是这么写的: // 警告:以下代码包含令人不适的内容,请谨慎观看login(username, password,function(token){getUserInfo(token,function(userInfo){getOrderList(userInfo.userId,

GLM-Image WebUI免配置教程:Gradio共享链接生成与内网穿透方案

GLM-Image WebUI免配置教程:Gradio共享链接生成与内网穿透方案 1. 项目简介与价值 智谱AI的GLM-Image是一个强大的文本到图像生成模型,能够根据文字描述创作出高质量的AI图像。但很多用户在本地部署后遇到了一个实际问题:生成的精美图片只能自己欣赏,无法方便地分享给朋友或同事。 这就是本文要解决的核心问题——如何在不进行复杂网络配置的情况下,让您的GLM-Image WebUI能够被其他人远程访问。我们将重点介绍两种简单实用的方法:Gradio自带的共享链接功能,以及更稳定的内网穿透方案。 无论您是设计师想要分享创作成果,还是开发者需要向团队成员演示AI生成效果,这篇文章都能帮您快速实现目标。 2. 环境准备与快速启动 在开始配置共享访问之前,请确保您的GLM-Image WebUI已经正常启动并运行。 2.1 检查服务状态 首先通过终端确认WebUI服务是否正常运行: # 检查服务进程 ps aux | grep gradio # 检查端口占用 netstat -tlnp | grep 7860 如果服务未启动,使用项目提供的启动脚本