目录
[3、go-view 路由守卫实现](#3、go-view 路由守卫实现)
[4、go-view 接口api实现](#4、go-view 接口api实现)
一、需求背景
搞来搞去,这个单点登录也是快搞疯了。
前期已经搞了3种方案了,客户还是不满意,感觉不够直接------需要有登陆过第三方应用或者授权。没有达到:
一次登录,多系统可用!
一次登录,多系统可用!
一次登录,多系统可用!
也就是常常听说的在任意一个系统中登陆一次,如果访问其他有权限的系统就直接可用访问有权限的内容,无需授权,无需再登陆。
-====== 相关文章 =======
ruoyi-vue-pro数据大屏------纯前端单点登录
二、解决方案
本方案以ruoyi-vue-pro后台管理应用 单点登录go-vue数据大屏为例。
1)ruoyi-vue-pro后台管理登陆成功后;
2)访问其他页面时,则将自己的的accessToken作为参数附加到url后,
例如: https://192.168.1.222:3000/big/?sso=${accessToken}
3)go-view数据大屏在路由守卫中对参数sso进行特别处理:
a)优先刷新本地可能留存的accessToken。
b)刷新失败,则通过accessToken完成一次登陆:
通过accessToken找到登陆过的user,完成自动登陆,返回新的accessToken。
c)go-view前端得到新的accessToken后,完成登陆后续过程,如获取用户菜单、权限等。
三、实现步骤
1、ruoyi-vue-pro通用页面
ruoyi-vue-pro后台管理应用参考前面的单点登陆文章配置好菜单,新建或修改 src\views\report\goview\bigscreen.vue,内容如下:
html
<template>
<div class="">
<i-frame v-if="url" :src="url" referrerpolicy="no-referrer"/>
</div>
</template>
<script>
import iFrame from "@/components/iFrame/index";
import * as auth from "@/utils/auth";
export default {
name: "BigScreen",
components: { iFrame },
props: {
/* 数据大屏的id */
value: {
type: String,
default: "",
},
},
data() {
return {
url: undefined,
};
},
mounted(){
var reportId = this.$route.params.id || this.$route.query.id || this.value
if(reportId){
this.url = this.setting.reportServer + "chart/preview/"+reportId+"?sso=" + auth.getAccessToken()+"&tenantId="+auth.getTenantId();
} else {
this.url = this.setting.reportServer + "?sso=" + auth.getAccessToken()+"&tenantId="+auth.getTenantId();
}
}
};
</script>
2、ruoyi-vue-pro后台管理后端逻辑实现src/main/java/com/more/doubleu/module/system/controller/admin/auth/AuthController.java
java
@PostMapping("/system/auth/sso-login/{t}")
@PermitAll
@Operation(summary = "访问令牌")
@Parameter(name = "t", description = "访问令牌", required = true, example = "")
@OperateLog(enable = false)
public CommonResult<AuthLoginRespVO> ssoLogin(@PathVariable("t") String token) {
AuthLoginRespVO authLoginRespVO = authService.ssoLogin(token);
return success(authLoginRespVO);
}
src/main/java/com/more/doubleu/module/system/service/auth/AdminAuthServiceImpl.java
java
@Override
public AuthLoginRespVO ssoLogin(String accessToken){
OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.checkAccessToken(accessToken);
AdminUserDO user = userService.getUser(accessTokenDO.getUserId());
if(user==null) {
throw new ServiceException(USER_NOT_EXISTS.getMsg());
}
// 创建 Token 令牌,记录登录日志
AuthLoginRespVO tokenAfterLoginSuccess = createTokenAfterLoginSuccess(user.getId(), user.getUsername(), LoginLogTypeEnum.LOGIN_USERNAME);
return tokenAfterLoginSuccess;
}
3、go-view 路由守卫实现
src\router\router-guards.ts
javascript
router.beforeEach(async (to, from, next) => {
// console.log(window['$t']('http.error_message'))
const Loading = window['$loading'];
Loading && Loading.start();
const isErrorPage = router.getRoutes().findIndex((item) => item.name === to.name);
if (isErrorPage === -1) {
next({ name: PageEnum.ERROR_PAGE_NAME_404 })
}
var query = to.query;
if(query && query.sso){
var tenantId = query.tenantId || App.setting.tenantId;
const info = getLocalStorage(StorageEnum.GO_SYSTEM_STORE)
const oldTenantId = info && info[SystemStoreEnum.TENANT_INFO] ? info[SystemStoreEnum.TENANT_INFO]['tenantId'] : undefined
// 清空本地存储
if(oldTenantId && oldTenantId!=tenantId) {
clearLocalStorage(StorageEnum.GO_SYSTEM_STORE);
clearLocalStorage(StorageEnum.GO_REFRESH_TOKEN);
}
let systemStore = useSystemStore();
systemStore.setItem(SystemStoreEnum.TENANT_INFO, {
tenantId: tenantId
})
// @ts-ignore
if (!routerAllowList.includes(to.name) && !loginCheck()) {
var refreshToken = await refreshTokenApi();
console.log("refreshToken 1", refreshToken)
if(refreshToken && refreshToken.code===0) {
await storeUserInfo(refreshToken);
} else {
var accessToken = await loginByAccessTokenApi(to.query.sso);
if(accessToken && accessToken.code===0) {
await storeUserInfo(accessToken);
}
}
}
}
// @ts-ignore
if (!routerAllowList.includes(to.name) && !loginCheck()) {
next({ name: PageEnum.BASE_LOGIN_NAME })
}
next()
})
4、go-view 接口api实现
src\api\path\system.api.ts
javascript
export const refreshTokenApi = async () => {
try {
var refreshToken = getLocalStorage(StorageEnum.GO_REFRESH_TOKEN).refreshToken;
if(refreshToken) {
const res = await http(RequestHttpEnum.POST)(`${ModuleTypeEnum.SYSTEM}/auth/refresh-token?refreshToken=` + refreshToken)
return res
}
} catch (err) {
clearLocalStorage(StorageEnum.GO_REFRESH_TOKEN);
}
return null;
}
// * 登录
export const loginByAccessTokenApi = async (accessToken: any) => {
try {
const res = await http(RequestHttpEnum.POST)<AuthLoginRespVO>(`${ModuleTypeEnum.SYSTEM}/auth/sso-login/${accessToken}`, {})
console.log(res)
return res
} catch (err) {
console.log(err)
}
return null;
}
export const storeUserInfo = async (loginRes:any) => {
let systemStore = useSystemStore();
if(loginRes && loginRes.data) {
// ① Token 信息(先存储下,保证可以加载个人信息)
setLocalStorage(StorageEnum.GO_REFRESH_TOKEN, loginRes.data);
const tokenValue = loginRes.data.accessToken
const tokenName = 'Authorization'
systemStore.setItem(SystemStoreEnum.USER_INFO, {
[SystemStoreUserInfoEnum.USER_TOKEN]: tokenValue,
[SystemStoreUserInfoEnum.TOKEN_NAME]: tokenName
})
// 个人信息
const profileRes:any = await getUserPermissionApi();
var user = profileRes.data.user;
const id = user.id
const username = user.username
const nickname = user.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,
});
}