Skip to content

Commit 0f0ba8b

Browse files
YunaiVgitee-org
authored andcommitted
!95 新增SSO登录
Merge pull request !95 from puhui999/dev
2 parents 1e0f613 + 841040b commit 0f0ba8b

File tree

13 files changed

+286
-24
lines changed

13 files changed

+286
-24
lines changed

.env.dev

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ VITE_API_BASEPATH=/dev-api
1616
VITE_API_URL=/admin-api
1717

1818
# 打包路径
19-
VITE_BASE_PATH=/dist-dev/
19+
VITE_BASE_PATH=/
2020

2121
# 是否删除debugger
2222
VITE_DROP_DEBUGGER=false

src/api/login/index.ts

Lines changed: 51 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,51 @@ export const getCode = (data) => {
7174
export const reqCheck = (data) => {
7275
return request.postOriginal({ url: 'system/captcha/check', data })
7376
}
77+
78+
// ========== OAUTH 2.0 相关 ==========
79+
export type scopesType = string[]
80+
export interface paramsType {
81+
responseType: string
82+
clientId: string
83+
redirectUri: string
84+
state: string
85+
scopes: scopesType
86+
}
87+
export const getAuthorize = (clientId) => {
88+
return request.get({ url: '/system/oauth2/authorize?clientId=' + clientId })
89+
}
90+
91+
export function authorize(
92+
responseType: string,
93+
clientId: string,
94+
redirectUri: string,
95+
state: string,
96+
autoApprove: boolean,
97+
checkedScopes: scopesType,
98+
uncheckedScopes: scopesType
99+
) {
100+
// 构建 scopes
101+
const scopes = {}
102+
for (const scope of checkedScopes) {
103+
scopes[scope] = true
104+
}
105+
for (const scope of uncheckedScopes) {
106+
scopes[scope] = false
107+
}
108+
// 发起请求
109+
return service({
110+
url: '/system/oauth2/authorize',
111+
headers: {
112+
'Content-type': 'application/x-www-form-urlencoded'
113+
},
114+
params: {
115+
response_type: responseType,
116+
client_id: clientId,
117+
redirect_uri: redirectUri,
118+
state: state,
119+
auto_approve: autoApprove,
120+
scope: JSON.stringify(scopes)
121+
},
122+
method: 'post'
123+
})
124+
}

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 = import.meta.env.VITE_BASE_PATH
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
},
@@ -352,6 +358,7 @@ export default {
352358
login: {
353359
backSignIn: '返回',
354360
signInFormTitle: '登录',
361+
ssoFormTitle: '三方授权',
355362
mobileSignInFormTitle: '手机登录',
356363
qrSignInFormTitle: '二维码登录',
357364
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 & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,14 @@ declare module '@vue/runtime-core' {
2121
Descriptions: typeof import('./../components/Descriptions/src/Descriptions.vue')['default']
2222
Dialog: typeof import('./../components/Dialog/src/Dialog.vue')['default']
2323
DictTag: typeof import('./../components/DictTag/src/DictTag.vue')['default']
24-
DocAlert: typeof import('./../components/DocAlert/index.vue')['default']
2524
Echart: typeof import('./../components/Echart/src/Echart.vue')['default']
2625
Editor: typeof import('./../components/Editor/src/Editor.vue')['default']
27-
ElAlert: typeof import('element-plus/es')['ElAlert']
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']
@@ -74,12 +73,8 @@ declare module '@vue/runtime-core' {
7473
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
7574
ElTabPane: typeof import('element-plus/es')['ElTabPane']
7675
ElTabs: typeof import('element-plus/es')['ElTabs']
77-
ElTag: typeof import('element-plus/es')['ElTag']
78-
ElTimeline: typeof import('element-plus/es')['ElTimeline']
79-
ElTimelineItem: typeof import('element-plus/es')['ElTimelineItem']
8076
ElTooltip: typeof import('element-plus/es')['ElTooltip']
8177
ElTree: typeof import('element-plus/es')['ElTree']
82-
ElTreeSelect: typeof import('element-plus/es')['ElTreeSelect']
8378
ElUpload: typeof import('element-plus/es')['ElUpload']
8479
Error: typeof import('./../components/Error/src/Error.vue')['default']
8580
FlowCondition: typeof import('./../components/bpmnProcessDesigner/package/penal/flow-condition/FlowCondition.vue')['default']

src/views/Login/Login.vue

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,19 @@
99
>
1010
<!-- 左上角的 logo + 系统标题 -->
1111
<div class="flex items-center relative text-white">
12-
<img src="@/assets/imgs/logo.png" alt="" class="w-48px h-48px mr-10px" />
12+
<img alt="" class="w-48px h-48px mr-10px" src="@/assets/imgs/logo.png" />
1313
<span class="text-20px font-bold">{{ underlineToHump(appStore.getTitle) }}</span>
1414
</div>
1515
<!-- 左边的背景图 + 欢迎语 -->
1616
<div class="flex justify-center items-center h-[calc(100%-60px)]">
1717
<TransitionGroup
1818
appear
19-
tag="div"
2019
enter-active-class="animate__animated animate__bounceInLeft"
20+
tag="div"
2121
>
22-
<img src="@/assets/svgs/login-box-bg.svg" key="1" alt="" class="w-350px" />
23-
<div class="text-3xl text-white" key="2">{{ t('login.welcome') }}</div>
24-
<div class="mt-5 font-normal text-white text-14px" key="3">
22+
<img key="1" alt="" class="w-350px" src="@/assets/svgs/login-box-bg.svg" />
23+
<div key="2" class="text-3xl text-white">{{ t('login.welcome') }}</div>
24+
<div key="3" class="mt-5 font-normal text-white text-14px">
2525
{{ t('login.message') }}
2626
</div>
2727
</TransitionGroup>
@@ -31,7 +31,7 @@
3131
<!-- 右上角的主题、语言选择 -->
3232
<div class="flex justify-between items-center text-white @2xl:justify-end @xl:justify-end">
3333
<div class="flex items-center @2xl:hidden @xl:hidden">
34-
<img src="@/assets/imgs/logo.png" alt="" class="w-48px h-48px mr-10px" />
34+
<img alt="" class="w-48px h-48px mr-10px" src="@/assets/imgs/logo.png" />
3535
<span class="text-20px font-bold">{{ underlineToHump(appStore.getTitle) }}</span>
3636
</div>
3737
<div class="flex justify-end items-center space-x-10px">
@@ -52,20 +52,23 @@
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+
<!-- 三方登录 -->
56+
<SSOLoginVue class="p-20px h-auto m-auto <xl:(rounded-3xl light:bg-white)" />
5557
</div>
5658
</Transition>
5759
</div>
5860
</div>
5961
</div>
6062
</template>
61-
<script setup lang="ts">
63+
<script lang="ts" setup>
6264
import { underlineToHump } from '@/utils'
6365
6466
import { useDesign } from '@/hooks/web/useDesign'
6567
import { useAppStore } from '@/store/modules/app'
6668
import { ThemeSwitch } from '@/layout/components/ThemeSwitch'
6769
import { LocaleDropdown } from '@/layout/components/LocaleDropdown'
68-
import { LoginForm, MobileForm, RegisterForm, QrCodeForm } from './components'
70+
71+
import { LoginForm, MobileForm, QrCodeForm, RegisterForm, SSOLoginVue } from './components'
6972
7073
const { t } = useI18n()
7174
const appStore = useAppStore()

src/views/Login/components/LoginForm.vue

Lines changed: 8 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 {
@@ -291,6 +296,7 @@ onMounted(() => {
291296
color: var(--el-color-primary) !important;
292297
}
293298
}
299+
294300
.login-code {
295301
width: 100%;
296302
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)