单点登录

This commit is contained in:
XinWei 2024-07-17 15:54:16 +08:00
parent f4a21daa0e
commit f000d0aa3f
5 changed files with 210 additions and 3 deletions

View File

@ -113,7 +113,7 @@ export default {
small: '小' small: '小'
}, },
login: { login: {
welcome: '欢迎使用本系统', welcome: '登录中心',
message: '开箱即用的中后台管理系统', message: '开箱即用的中后台管理系统',
tenantname: '租户名称', tenantname: '租户名称',
username: '用户名', username: '用户名',

View File

@ -186,7 +186,7 @@ const remainingRouter: AppRouteRecordRaw[] = [
}, },
{ {
path: '/sso', path: '/sso',
component: () => import('@/views/Login/Login.vue'), component: () => import('@/views/Login/components/SSOLoginCustom.vue'),
name: 'SSOLogin', name: 'SSOLogin',
meta: { meta: {
hidden: true, hidden: true,

View File

@ -20,12 +20,14 @@ export const getRefreshToken = () => {
// 设置token // 设置token
export const setToken = (token: TokenType) => { export const setToken = (token: TokenType) => {
document.cookie = "LUNDU_LOGIN=true; max-age=1800; path=/"; // 设置cookie登录状态
wsCache.set(RefreshTokenKey, token.refreshToken) wsCache.set(RefreshTokenKey, token.refreshToken)
wsCache.set(AccessTokenKey, token.accessToken) wsCache.set(AccessTokenKey, token.accessToken)
} }
// 删除token // 删除token
export const removeToken = () => { export const removeToken = () => {
document.cookie = "LUNDU_LOGIN=false; max-age=0; path=/"; // 清除cookie登录状态
wsCache.delete(AccessTokenKey) wsCache.delete(AccessTokenKey)
wsCache.delete(RefreshTokenKey) wsCache.delete(RefreshTokenKey)
} }

View File

@ -55,7 +55,9 @@
</el-skeleton> </el-skeleton>
</el-card> </el-card>
</div> </div>
<div class="flex flex-wrap gap-4" style="margin: 20px 0;">
<el-card style="width: 420px;text-align: center;cursor: pointer;" shadow="hover" @click="goToXXLJob">任务调度中心</el-card>
</div>
<!-- <el-row class="mt-8px" :gutter="8" justify="space-between"> <!-- <el-row class="mt-8px" :gutter="8" justify="space-between">
<el-col :xl="16" :lg="16" :md="24" :sm="24" :xs="24" class="mb-8px"> <el-col :xl="16" :lg="16" :md="24" :sm="24" :xs="24" class="mb-8px">
<el-card shadow="never"> <el-card shadow="never">
@ -387,5 +389,8 @@ const getAllApi = async () => {
loading.value = false loading.value = false
} }
const goToXXLJob = async () => {
window.location.href = 'http://127.0.0.1:9090/xxl-job-admin/'
}
getAllApi() getAllApi()
</script> </script>

View File

@ -0,0 +1,200 @@
<template>
<div v-show="false" class="form-cont">
<!-- 应用名 -->
<LoginFormTitle style="width: 100%" />
<el-tabs class="form" style="float: none" value="uname">
<el-tab-pane :label="client.name" name="uname" />
</el-tabs>
<div>
<el-form :model="formData" class="login-form">
<!-- 授权范围的选择 -->
此第三方应用请求获得以下权限
<el-form-item prop="scopes">
<el-checkbox-group v-model="formData.scopes">
<el-checkbox
v-for="scope in queryParams.scopes"
:key="scope"
:label="scope"
style="display: block; margin-bottom: -10px"
>
{{ formatScope(scope) }}
</el-checkbox>
</el-checkbox-group>
</el-form-item>
<!-- 下方的登录按钮 -->
<el-form-item class="w-1/1">
<el-button
:loading="formLoading"
class="w-6/10"
type="primary"
@click.prevent="handleAuthorize(true)"
>
<span v-if="!formLoading">同意授权</span>
<span v-else> 中...</span>
</el-button>
<el-button class="w-3/10" @click.prevent="handleAuthorize(false)">拒绝</el-button>
</el-form-item>
</el-form>
</div>
</div>
</template>
<script lang="ts" setup>
import LoginFormTitle from './LoginFormTitle.vue'
import * as OAuth2Api from '@/api/login/oauth2'
import { LoginStateEnum, useLoginState } from './useLogin'
import type { RouteLocationNormalizedLoaded } from 'vue-router'
defineOptions({ name: 'SSOLogin' })
const route = useRoute() //
const { currentRoute } = useRouter() //
const { getLoginState, setLoginState } = useLoginState()
const client = ref({
//
name: '',
logo: ''
})
interface queryType {
responseType: string
clientId: string
redirectUri: string
state: string
scopes: string[]
}
const queryParams = reactive<queryType>({
// URL client_idscope
responseType: '',
clientId: '',
redirectUri: '',
state: '',
scopes: [] // query
})
const ssoVisible = computed(() => unref(getLoginState) === LoginStateEnum.SSO) // SSO
interface formType {
scopes: string[]
}
const formData = reactive<formType>({
scopes: [] // scope
})
const formLoading = ref(false) //
/** 初始化授权信息 */
const init = async () => {
//
if (typeof route.query.client_id === 'undefined') return
//
// client_id=default&redirect_uri=https%3A%2F%2Fwww.iocoder.cn&response_type=code&scope=user.read%20user.write
// client_id=default&redirect_uri=https%3A%2F%2Fwww.iocoder.cn&response_type=code&scope=user.read
queryParams.responseType = route.query.response_type as string
queryParams.clientId = route.query.client_id as string
queryParams.redirectUri = route.query.redirect_uri as string
queryParams.state = route.query.state as string
if (route.query.scope) {
queryParams.scopes = (route.query.scope as string).split(' ')
}
// scope
if (queryParams.scopes.length > 0) {
const data = await doAuthorize(true, queryParams.scopes, [])
if (data) {
location.href = data
return
}
}
//
const data = await OAuth2Api.getAuthorize(queryParams.clientId)
client.value = data.client
// scope
let scopes
// 1.1 params.scope scopes
if (queryParams.scopes.length > 0) {
scopes = []
for (const scope of data.scopes) {
if (queryParams.scopes.indexOf(scope.key) >= 0) {
scopes.push(scope)
}
}
// 1.2 params.scope 使 scopes
} else {
scopes = data.scopes
for (const scope of scopes) {
queryParams.scopes.push(scope.key)
}
}
// checkedScopes
for (const scope of scopes) {
if (scope.value) {
formData.scopes.push(scope.key)
}
}
}
/** 处理授权的提交 */
const handleAuthorize = async (approved) => {
// checkedScopes + uncheckedScopes
let checkedScopes
let uncheckedScopes
if (approved) {
//
checkedScopes = queryParams.scopes
uncheckedScopes = queryParams.scopes.filter((item) => checkedScopes.indexOf(item) === -1)
} else {
//
checkedScopes = []
uncheckedScopes = queryParams.scopes
}
//
formLoading.value = true
try {
const data = await doAuthorize(false, checkedScopes, uncheckedScopes)
if (!data) {
return
}
location.href = data
} finally {
formLoading.value = false
}
}
/** 调用授权 API 接口 */
const doAuthorize = (autoApprove, checkedScopes, uncheckedScopes) => {
return OAuth2Api.authorize(
queryParams.responseType,
queryParams.clientId,
queryParams.redirectUri,
queryParams.state,
autoApprove,
checkedScopes,
uncheckedScopes
)
}
/** 格式化 scope 文本 */
const formatScope = (scope) => {
// scope 便
// demo "system_oauth2_scope" scope
switch (scope) {
case 'user.read':
return '访问你的个人信息'
case 'user.write':
return '修改你的个人信息'
default:
return scope
}
}
/** 监听当前路由为 SSOLogin 时,进行数据的初始化 */
watch(
() => currentRoute.value,
async (route: RouteLocationNormalizedLoaded) => {
if (route.name === 'SSOLogin') {
setLoginState(LoginStateEnum.SSO)
await init()
handleAuthorize(true)
}
},
{ immediate: true }
)
</script>