完善SSO单点登录
This commit is contained in:
parent
2d019f1bf9
commit
e22363d061
@ -76,7 +76,14 @@ export const reqCheckApi = (data) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ========== OAUTH 2.0 相关 ==========
|
// ========== OAUTH 2.0 相关 ==========
|
||||||
|
export type scopesType = string[]
|
||||||
|
export interface paramsType {
|
||||||
|
responseType: string
|
||||||
|
clientId: string
|
||||||
|
redirectUri: string
|
||||||
|
state: string
|
||||||
|
scopes: scopesType
|
||||||
|
}
|
||||||
export const getAuthorize = (clientId) => {
|
export const getAuthorize = (clientId) => {
|
||||||
return request.get({ url: '/system/oauth2/authorize?clientId=' + clientId })
|
return request.get({ url: '/system/oauth2/authorize?clientId=' + clientId })
|
||||||
}
|
}
|
||||||
@ -87,8 +94,8 @@ export function authorize(
|
|||||||
redirectUri: string,
|
redirectUri: string,
|
||||||
state: string,
|
state: string,
|
||||||
autoApprove: boolean,
|
autoApprove: boolean,
|
||||||
checkedScopes: any,
|
checkedScopes: scopesType,
|
||||||
uncheckedScopes: any
|
uncheckedScopes: scopesType
|
||||||
) {
|
) {
|
||||||
// 构建 scopes
|
// 构建 scopes
|
||||||
const scopes = {}
|
const scopes = {}
|
||||||
|
@ -9,19 +9,19 @@
|
|||||||
>
|
>
|
||||||
<!-- 左上角的 logo + 系统标题 -->
|
<!-- 左上角的 logo + 系统标题 -->
|
||||||
<div class="flex items-center relative text-white">
|
<div class="flex items-center relative text-white">
|
||||||
<img src="@/assets/imgs/logo.png" alt="" class="w-48px h-48px mr-10px" />
|
<img alt="" class="w-48px h-48px mr-10px" src="@/assets/imgs/logo.png" />
|
||||||
<span class="text-20px font-bold">{{ underlineToHump(appStore.getTitle) }}</span>
|
<span class="text-20px font-bold">{{ underlineToHump(appStore.getTitle) }}</span>
|
||||||
</div>
|
</div>
|
||||||
<!-- 左边的背景图 + 欢迎语 -->
|
<!-- 左边的背景图 + 欢迎语 -->
|
||||||
<div class="flex justify-center items-center h-[calc(100%-60px)]">
|
<div class="flex justify-center items-center h-[calc(100%-60px)]">
|
||||||
<TransitionGroup
|
<TransitionGroup
|
||||||
appear
|
appear
|
||||||
tag="div"
|
|
||||||
enter-active-class="animate__animated animate__bounceInLeft"
|
enter-active-class="animate__animated animate__bounceInLeft"
|
||||||
|
tag="div"
|
||||||
>
|
>
|
||||||
<img src="@/assets/svgs/login-box-bg.svg" key="1" alt="" class="w-350px" />
|
<img key="1" alt="" class="w-350px" src="@/assets/svgs/login-box-bg.svg" />
|
||||||
<div class="text-3xl text-white" key="2">{{ t('login.welcome') }}</div>
|
<div key="2" class="text-3xl text-white">{{ t('login.welcome') }}</div>
|
||||||
<div class="mt-5 font-normal text-white text-14px" key="3">
|
<div key="3" class="mt-5 font-normal text-white text-14px">
|
||||||
{{ t('login.message') }}
|
{{ t('login.message') }}
|
||||||
</div>
|
</div>
|
||||||
</TransitionGroup>
|
</TransitionGroup>
|
||||||
@ -31,7 +31,7 @@
|
|||||||
<!-- 右上角的主题、语言选择 -->
|
<!-- 右上角的主题、语言选择 -->
|
||||||
<div class="flex justify-between items-center text-white @2xl:justify-end @xl:justify-end">
|
<div class="flex justify-between items-center text-white @2xl:justify-end @xl:justify-end">
|
||||||
<div class="flex items-center @2xl:hidden @xl:hidden">
|
<div class="flex items-center @2xl:hidden @xl:hidden">
|
||||||
<img src="@/assets/imgs/logo.png" alt="" class="w-48px h-48px mr-10px" />
|
<img alt="" class="w-48px h-48px mr-10px" src="@/assets/imgs/logo.png" />
|
||||||
<span class="text-20px font-bold">{{ underlineToHump(appStore.getTitle) }}</span>
|
<span class="text-20px font-bold">{{ underlineToHump(appStore.getTitle) }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-end items-center space-x-10px">
|
<div class="flex justify-end items-center space-x-10px">
|
||||||
@ -52,18 +52,15 @@
|
|||||||
<QrCodeForm class="p-20px h-auto m-auto <xl:(rounded-3xl light:bg-white)" />
|
<QrCodeForm class="p-20px h-auto m-auto <xl:(rounded-3xl light:bg-white)" />
|
||||||
<!-- 注册 -->
|
<!-- 注册 -->
|
||||||
<RegisterForm class="p-20px h-auto m-auto <xl:(rounded-3xl light:bg-white)" />
|
<RegisterForm class="p-20px h-auto m-auto <xl:(rounded-3xl light:bg-white)" />
|
||||||
<!-- 三方登录 v-if触发组件初始化 -->
|
<!-- 三方登录 -->
|
||||||
<SSOLoginVue
|
<SSOLoginVue class="p-20px h-auto m-auto <xl:(rounded-3xl light:bg-white)" />
|
||||||
v-if="isSSO"
|
|
||||||
class="p-20px h-auto m-auto <xl:(rounded-3xl light:bg-white)"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</Transition>
|
</Transition>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script lang="ts" setup>
|
||||||
import { underlineToHump } from '@/utils'
|
import { underlineToHump } from '@/utils'
|
||||||
|
|
||||||
import { useDesign } from '@/hooks/web/useDesign'
|
import { useDesign } from '@/hooks/web/useDesign'
|
||||||
@ -72,23 +69,11 @@ import { ThemeSwitch } from '@/layout/components/ThemeSwitch'
|
|||||||
import { LocaleDropdown } from '@/layout/components/LocaleDropdown'
|
import { LocaleDropdown } from '@/layout/components/LocaleDropdown'
|
||||||
|
|
||||||
import { LoginForm, MobileForm, QrCodeForm, RegisterForm, SSOLoginVue } from './components'
|
import { LoginForm, MobileForm, QrCodeForm, RegisterForm, SSOLoginVue } from './components'
|
||||||
import { RouteLocationNormalizedLoaded } from 'vue-router'
|
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
const appStore = useAppStore()
|
const appStore = useAppStore()
|
||||||
const { getPrefixCls } = useDesign()
|
const { getPrefixCls } = useDesign()
|
||||||
const prefixCls = getPrefixCls('login')
|
const prefixCls = getPrefixCls('login')
|
||||||
// =======SSO======
|
|
||||||
const isSSO = ref(false)
|
|
||||||
const router = useRouter()
|
|
||||||
// 监听当前路由
|
|
||||||
watch(
|
|
||||||
() => router.currentRoute.value,
|
|
||||||
(route: RouteLocationNormalizedLoaded) => {
|
|
||||||
if (route.name === 'SSOLogin') isSSO.value = true
|
|
||||||
},
|
|
||||||
{ immediate: true }
|
|
||||||
)
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@ -279,7 +279,6 @@ const doSocialLogin = async (type: number) => {
|
|||||||
watch(
|
watch(
|
||||||
() => currentRoute.value,
|
() => currentRoute.value,
|
||||||
(route: RouteLocationNormalizedLoaded) => {
|
(route: RouteLocationNormalizedLoaded) => {
|
||||||
if (route.name === 'SSOLogin') setLoginState(LoginStateEnum.SSO)
|
|
||||||
redirect.value = route?.query?.redirect as string
|
redirect.value = route?.query?.redirect as string
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<!-- 表单 -->
|
<!-- 表单 -->
|
||||||
<div class="form-cont">
|
<div v-show="getShow" class="form-cont">
|
||||||
|
<!-- <LoginFormTitle style="width: 100%" />-->
|
||||||
<el-tabs class="form" style="float: none" value="uname">
|
<el-tabs class="form" style="float: none" value="uname">
|
||||||
<el-tab-pane :label="'三方授权(' + client.name + ')'" name="uname" />
|
<el-tab-pane :label="'三方授权(' + client.name + ')'" name="uname" />
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
@ -12,8 +13,8 @@
|
|||||||
<el-checkbox-group v-model="loginForm.scopes">
|
<el-checkbox-group v-model="loginForm.scopes">
|
||||||
<el-checkbox
|
<el-checkbox
|
||||||
v-for="scope in params.scopes"
|
v-for="scope in params.scopes"
|
||||||
:label="scope"
|
|
||||||
:key="scope"
|
:key="scope"
|
||||||
|
:label="scope"
|
||||||
style="display: block; margin-bottom: -10px"
|
style="display: block; margin-bottom: -10px"
|
||||||
>{{ formatScope(scope) }}
|
>{{ formatScope(scope) }}
|
||||||
</el-checkbox>
|
</el-checkbox>
|
||||||
@ -24,8 +25,8 @@
|
|||||||
<el-button
|
<el-button
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
size="small"
|
size="small"
|
||||||
type="primary"
|
|
||||||
style="width: 60%"
|
style="width: 60%"
|
||||||
|
type="primary"
|
||||||
@click.prevent="handleAuthorize(true)"
|
@click.prevent="handleAuthorize(true)"
|
||||||
>
|
>
|
||||||
<span v-if="!loading">同意授权</span>
|
<span v-if="!loading">同意授权</span>
|
||||||
@ -40,19 +41,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" name="SSOLogin" setup>
|
<script lang="ts" name="SSOLogin" setup>
|
||||||
import { authorize, getAuthorize } from '@/api/login'
|
// import LoginFormTitle from './LoginFormTitle.vue' // TODO 艿艿你看看要不要这个表头
|
||||||
|
import { authorize, getAuthorize, paramsType, scopesType } from '@/api/login'
|
||||||
|
import { LoginStateEnum, useLoginState } from './useLogin'
|
||||||
|
import type { RouteLocationNormalizedLoaded } from 'vue-router'
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
const ssoForm = ref() // 表单Ref
|
const ssoForm = ref() // 表单Ref
|
||||||
|
const { getLoginState, setLoginState } = useLoginState()
|
||||||
type scopesType = string[]
|
const getShow = computed(() => unref(getLoginState) === LoginStateEnum.SSO)
|
||||||
interface paramsType {
|
|
||||||
responseType: string
|
|
||||||
clientId: string
|
|
||||||
redirectUri: string
|
|
||||||
state: string
|
|
||||||
scopes: scopesType
|
|
||||||
}
|
|
||||||
const loginForm = reactive<{ scopes: scopesType }>({
|
const loginForm = reactive<{ scopes: scopesType }>({
|
||||||
scopes: [] // 已选中的 scope 数组
|
scopes: [] // 已选中的 scope 数组
|
||||||
})
|
})
|
||||||
@ -116,6 +113,7 @@ const doAuthorize = (autoApprove, checkedScopes, uncheckedScopes) => {
|
|||||||
const formatScope = (scope) => {
|
const formatScope = (scope) => {
|
||||||
// 格式化 scope 授权范围,方便用户理解。
|
// 格式化 scope 授权范围,方便用户理解。
|
||||||
// 这里仅仅是一个 demo,可以考虑录入到字典数据中,例如说字典类型 "system_oauth2_scope",它的每个 scope 都是一条字典数据。
|
// 这里仅仅是一个 demo,可以考虑录入到字典数据中,例如说字典类型 "system_oauth2_scope",它的每个 scope 都是一条字典数据。
|
||||||
|
// TODO 这个之做了中文部分
|
||||||
return t(`login.sso.${scope}`)
|
return t(`login.sso.${scope}`)
|
||||||
}
|
}
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
@ -146,7 +144,6 @@ const init = () => {
|
|||||||
|
|
||||||
// 获取授权页的基本信息
|
// 获取授权页的基本信息
|
||||||
getAuthorize(params.clientId).then((res) => {
|
getAuthorize(params.clientId).then((res) => {
|
||||||
console.log(res)
|
|
||||||
client.value = res.client
|
client.value = res.client
|
||||||
// 解析 scope
|
// 解析 scope
|
||||||
let scopes
|
let scopes
|
||||||
@ -173,5 +170,18 @@ const init = () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
// =======SSO======
|
||||||
|
const { currentRoute } = useRouter()
|
||||||
|
// 监听当前路由
|
||||||
|
watch(
|
||||||
|
() => currentRoute.value,
|
||||||
|
(route: RouteLocationNormalizedLoaded) => {
|
||||||
|
if (route.name === 'SSOLogin') {
|
||||||
|
setLoginState(LoginStateEnum.SSO)
|
||||||
|
init()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
)
|
||||||
init()
|
init()
|
||||||
</script>
|
</script>
|
||||||
|
Loading…
Reference in New Issue
Block a user