Skip to content

Commit 2d019f1

Browse files
author
puhui999
committed
增加SSO单点登录
1 parent f16ea74 commit 2d019f1

File tree

12 files changed

+277
-23
lines changed

12 files changed

+277
-23
lines changed

src/api/login/index.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
11
import request from '@/config/axios'
22
import { getRefreshToken } from '@/utils/auth'
33
import type { UserLoginVO } from './types'
4+
import { service } from '@/config/axios/service'
45

56
export interface CodeImgResult {
67
captchaOnOff: boolean
78
img: string
89
uuid: string
910
}
11+
1012
export interface SmsCodeVO {
1113
mobile: string
1214
scene: number
1315
}
16+
1417
export interface SmsLoginVO {
1518
mobile: string
1619
code: string
@@ -71,3 +74,44 @@ export const getCodeApi = (data) => {
7174
export const reqCheckApi = (data) => {
7275
return request.postOriginal({ url: 'system/captcha/check', data })
7376
}
77+
78+
// ========== OAUTH 2.0 相关 ==========
79+
80+
export const getAuthorize = (clientId) => {
81+
return request.get({ url: '/system/oauth2/authorize?clientId=' + clientId })
82+
}
83+
84+
export function authorize(
85+
responseType: string,
86+
clientId: string,
87+
redirectUri: string,
88+
state: string,
89+
autoApprove: boolean,
90+
checkedScopes: any,
91+
uncheckedScopes: any
92+
) {
93+
// 构建 scopes
94+
const scopes = {}
95+
for (const scope of checkedScopes) {
96+
scopes[scope] = true
97+
}
98+
for (const scope of uncheckedScopes) {
99+
scopes[scope] = false
100+
}
101+
// 发起请求
102+
return service({
103+
url: '/system/oauth2/authorize',
104+
headers: {
105+
'Content-type': 'application/x-www-form-urlencoded'
106+
},
107+
params: {
108+
response_type: responseType,
109+
client_id: clientId,
110+
redirect_uri: redirectUri,
111+
state: state,
112+
auto_approve: autoApprove,
113+
scope: JSON.stringify(scopes)
114+
},
115+
method: 'post'
116+
})
117+
}

src/config/axios/service.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import axios, {
2+
AxiosError,
23
AxiosInstance,
34
AxiosRequestHeaders,
45
AxiosResponse,
5-
AxiosError,
66
InternalAxiosRequestConfig
77
} from 'axios'
88

@@ -230,7 +230,7 @@ const handleAuthorized = () => {
230230
wsCache.clear()
231231
removeToken()
232232
isRelogin.show = false
233-
window.location.href = '/'
233+
window.location.href = '/login?redirect=/sso?' + window.location.href.split('?')[1]
234234
})
235235
}
236236
return Promise.reject(t('sys.api.timeoutMessage'))

src/locales/zh-CN.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,12 @@ export default {
129129
btnMobile: '手机登录',
130130
btnQRCode: '二维码登录',
131131
qrcode: '扫描二维码登录',
132+
sso: {
133+
user: {
134+
read: '访问你的个人信息',
135+
write: '修改你的个人信息'
136+
}
137+
},
132138
btnRegister: '注册',
133139
SmsSendMsg: '验证码已发送'
134140
},
@@ -353,6 +359,7 @@ export default {
353359
login: {
354360
backSignIn: '返回',
355361
signInFormTitle: '登录',
362+
ssoFormTitle: '三方授权',
356363
mobileSignInFormTitle: '手机登录',
357364
qrSignInFormTitle: '二维码登录',
358365
signUpFormTitle: '注册',

src/router/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import type { App } from 'vue'
22
import type { RouteRecordRaw } from 'vue-router'
3-
import { createRouter, createWebHashHistory } from 'vue-router'
3+
import { createRouter, createWebHistory } from 'vue-router'
44
import remainingRouter from './modules/remaining'
55

66
// 创建路由实例
77
const router = createRouter({
8-
history: createWebHashHistory(), // createWebHashHistory URL带#,createWebHistory URL不带#
8+
history: createWebHistory(), // createWebHashHistory URL带#,createWebHistory URL不带#
99
strict: true,
1010
routes: remainingRouter as RouteRecordRaw[],
1111
scrollBehavior: () => ({ left: 0, top: 0 })

src/router/modules/remaining.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,16 @@ const remainingRouter: AppRouteRecordRaw[] = [
185185
noTagsView: true
186186
}
187187
},
188+
{
189+
path: '/sso',
190+
component: () => import('@/views/Login/Login.vue'),
191+
name: 'SSOLogin',
192+
meta: {
193+
hidden: true,
194+
title: t('router.login'),
195+
noTagsView: true
196+
}
197+
},
188198
{
189199
path: '/403',
190200
component: () => import('@/views/Error/403.vue'),

src/types/auto-components.d.ts

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,12 @@ declare module '@vue/runtime-core' {
2323
DictTag: typeof import('./../components/DictTag/src/DictTag.vue')['default']
2424
Echart: typeof import('./../components/Echart/src/Echart.vue')['default']
2525
Editor: typeof import('./../components/Editor/src/Editor.vue')['default']
26-
ElAutoResizer: typeof import('element-plus/es')['ElAutoResizer']
27-
ElAvatar: typeof import('element-plus/es')['ElAvatar']
2826
ElBadge: typeof import('element-plus/es')['ElBadge']
2927
ElButton: typeof import('element-plus/es')['ElButton']
3028
ElButtonGroup: typeof import('element-plus/es')['ElButtonGroup']
3129
ElCard: typeof import('element-plus/es')['ElCard']
3230
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
31+
ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup']
3332
ElCol: typeof import('element-plus/es')['ElCol']
3433
ElCollapse: typeof import('element-plus/es')['ElCollapse']
3534
ElCollapseItem: typeof import('element-plus/es')['ElCollapseItem']
@@ -54,34 +53,23 @@ declare module '@vue/runtime-core' {
5453
ElForm: typeof import('element-plus/es')['ElForm']
5554
ElFormItem: typeof import('element-plus/es')['ElFormItem']
5655
ElIcon: typeof import('element-plus/es')['ElIcon']
57-
ElImage: typeof import('element-plus/es')['ElImage']
5856
ElImageViewer: typeof import('element-plus/es')['ElImageViewer']
5957
ElInput: typeof import('element-plus/es')['ElInput']
60-
ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
6158
ElLink: typeof import('element-plus/es')['ElLink']
6259
ElOption: typeof import('element-plus/es')['ElOption']
6360
ElPagination: typeof import('element-plus/es')['ElPagination']
6461
ElPopover: typeof import('element-plus/es')['ElPopover']
65-
ElRadio: typeof import('element-plus/es')['ElRadio']
66-
ElRadioButton: typeof import('element-plus/es')['ElRadioButton']
67-
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
6862
ElRow: typeof import('element-plus/es')['ElRow']
6963
ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
7064
ElSelect: typeof import('element-plus/es')['ElSelect']
7165
ElSkeleton: typeof import('element-plus/es')['ElSkeleton']
72-
ElSpace: typeof import('element-plus/es')['ElSpace']
7366
ElSwitch: typeof import('element-plus/es')['ElSwitch']
7467
ElTable: typeof import('element-plus/es')['ElTable']
7568
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
76-
ElTableV2: typeof import('element-plus/es')['ElTableV2']
7769
ElTabPane: typeof import('element-plus/es')['ElTabPane']
7870
ElTabs: typeof import('element-plus/es')['ElTabs']
79-
ElTag: typeof import('element-plus/es')['ElTag']
80-
ElTimeline: typeof import('element-plus/es')['ElTimeline']
81-
ElTimelineItem: typeof import('element-plus/es')['ElTimelineItem']
8271
ElTooltip: typeof import('element-plus/es')['ElTooltip']
8372
ElTree: typeof import('element-plus/es')['ElTree']
84-
ElTreeSelect: typeof import('element-plus/es')['ElTreeSelect']
8573
ElUpload: typeof import('element-plus/es')['ElUpload']
8674
Error: typeof import('./../components/Error/src/Error.vue')['default']
8775
FlowCondition: typeof import('./../components/bpmnProcessDesigner/package/penal/flow-condition/FlowCondition.vue')['default']

src/views/Login/Login.vue

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@
5252
<QrCodeForm class="p-20px h-auto m-auto <xl:(rounded-3xl light:bg-white)" />
5353
<!-- 注册 -->
5454
<RegisterForm class="p-20px h-auto m-auto <xl:(rounded-3xl light:bg-white)" />
55+
<!-- 三方登录 v-if触发组件初始化 -->
56+
<SSOLoginVue
57+
v-if="isSSO"
58+
class="p-20px h-auto m-auto <xl:(rounded-3xl light:bg-white)"
59+
/>
5560
</div>
5661
</Transition>
5762
</div>
@@ -65,12 +70,25 @@ import { useDesign } from '@/hooks/web/useDesign'
6570
import { useAppStore } from '@/store/modules/app'
6671
import { ThemeSwitch } from '@/layout/components/ThemeSwitch'
6772
import { LocaleDropdown } from '@/layout/components/LocaleDropdown'
68-
import { LoginForm, MobileForm, RegisterForm, QrCodeForm } from './components'
73+
74+
import { LoginForm, MobileForm, QrCodeForm, RegisterForm, SSOLoginVue } from './components'
75+
import { RouteLocationNormalizedLoaded } from 'vue-router'
6976
7077
const { t } = useI18n()
7178
const appStore = useAppStore()
7279
const { getPrefixCls } = useDesign()
7380
const prefixCls = getPrefixCls('login')
81+
// =======SSO======
82+
const isSSO = ref(false)
83+
const router = useRouter()
84+
// 监听当前路由
85+
watch(
86+
() => router.currentRoute.value,
87+
(route: RouteLocationNormalizedLoaded) => {
88+
if (route.name === 'SSOLogin') isSSO.value = true
89+
},
90+
{ immediate: true }
91+
)
7492
</script>
7593

7694
<style lang="scss" scoped>

src/views/Login/components/LoginForm.vue

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ import { useIcon } from '@/hooks/web/useIcon'
137137
import * as authUtil from '@/utils/auth'
138138
import { usePermissionStore } from '@/store/modules/permission'
139139
import * as LoginApi from '@/api/login'
140-
import { LoginStateEnum, useLoginState, useFormValid } from './useLogin'
140+
import { LoginStateEnum, useFormValid, useLoginState } from './useLogin'
141141
142142
const { t } = useI18n()
143143
const message = useMessage()
@@ -240,7 +240,12 @@ const handleLogin = async (params) => {
240240
if (!redirect.value) {
241241
redirect.value = '/'
242242
}
243-
push({ path: redirect.value || permissionStore.addRouters[0].path })
243+
// 判断是否为SSO登录
244+
if (redirect.value.indexOf('sso') !== -1) {
245+
window.location.href = window.location.href.replace('/login?redirect=', '')
246+
} else {
247+
push({ path: redirect.value || permissionStore.addRouters[0].path })
248+
}
244249
} catch {
245250
loginLoading.value = false
246251
} finally {
@@ -274,6 +279,7 @@ const doSocialLogin = async (type: number) => {
274279
watch(
275280
() => currentRoute.value,
276281
(route: RouteLocationNormalizedLoaded) => {
282+
if (route.name === 'SSOLogin') setLoginState(LoginStateEnum.SSO)
277283
redirect.value = route?.query?.redirect as string
278284
},
279285
{
@@ -291,6 +297,7 @@ onMounted(() => {
291297
color: var(--el-color-primary) !important;
292298
}
293299
}
300+
294301
.login-code {
295302
width: 100%;
296303
height: 38px;

src/views/Login/components/LoginFormTitle.vue

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ const getFormTitle = computed(() => {
1616
[LoginStateEnum.LOGIN]: t('sys.login.signInFormTitle'),
1717
[LoginStateEnum.REGISTER]: t('sys.login.signUpFormTitle'),
1818
[LoginStateEnum.MOBILE]: t('sys.login.mobileSignInFormTitle'),
19-
[LoginStateEnum.QR_CODE]: t('sys.login.qrSignInFormTitle')
19+
[LoginStateEnum.QR_CODE]: t('sys.login.qrSignInFormTitle'),
20+
[LoginStateEnum.SSO]: t('sys.login.ssoFormTitle')
2021
}
2122
return titleObj[unref(getLoginState)]
2223
})

0 commit comments

Comments
 (0)