数据大屏-单点登录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,内容如下:

javascript 复制代码
<template>
  <!-- 登录 -->
  <div class="go-login-box">
    
  </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,在后面新增代码:

javascript 复制代码
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如下:

javascript 复制代码
// * SSO登录
// 可以改写成,你的 clientId
const clientId = 'report';

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文件中判断白名单前,新增代码如下:

javascript 复制代码
    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中配置菜单直接访问数据看板

相关推荐
C澒12 小时前
SGW 接入层运维实战:配置查看 + 监控分析 + 日志排查
前端·安全·运维开发
德育处主任Pro12 小时前
『NAS』在群晖部署一款太空策略游戏-ogame-vue-ts
前端·vue.js·游戏
ziqi52213 小时前
第二十五天笔记
前端·chrome·笔记
GISer_Jing13 小时前
Memory、Rules、Skills、MCP如何重塑AI编程
前端·人工智能·aigc·ai编程
xcs1940513 小时前
前端 项目构建问题 \node_modules\loader-runner\lib\loadLoader.js
开发语言·前端·javascript
广然13 小时前
EVE-NG 镜像管理工具 1.1 Web 版本正式发布!
运维·服务器·前端
Data_Journal13 小时前
【无标题】
大数据·服务器·前端·数据库·人工智能
我爱加班、、13 小时前
new Map()+Array.from()整理elementPlus的级联器数据
linux·前端·javascript
Hx_Ma1613 小时前
Map集合的5种遍历方式
java·前端·javascript
css趣多多13 小时前
render函数
前端·javascript·vue.js