数据大屏-单点登录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中配置菜单直接访问数据看板

相关推荐
我想回家种地18 小时前
python期末复习重点
前端·javascript·python
行者9618 小时前
Flutter适配OpenHarmony:高效数据筛选组件的设计与实现
开发语言·前端·flutter·harmonyos·鸿蒙
Van_Moonlight18 小时前
RN for OpenHarmony 实战 TodoList 项目:底部 Tab 栏
javascript·开源·harmonyos
Van_Moonlight18 小时前
RN for OpenHarmony 实战 TodoList 项目:浮动添加按钮 FAB
javascript·开源·harmonyos
Serendipity-Solitude19 小时前
HTML 五子棋实现方法
前端·html
frontend_frank19 小时前
脱离 Electron autoUpdater:uni-app跨端更新:Windows+Android统一实现方案
android·前端·javascript·electron·uni-app
PieroPC19 小时前
用FastAPI 一个 后端 和 两个前端 原生HTML/CSS/JS 、Vue3 写一个博客系统 例
前端·后端
wulijuan88866619 小时前
BroadcastChannel API 同源的多个标签页可以使用 BroadcastChannel 进行通讯
前端·javascript·vue.js
kilito_0119 小时前
数字时钟翻页效果
javascript·css·css3