@pubinfo-pr/module-auth 0.203.1 → 0.203.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth.d.ts +9 -0
- package/dist/core.d.ts +43 -25
- package/dist/helper.d.ts +1 -6
- package/dist/index.d.ts +20 -4
- package/dist/index.js +151 -101
- package/dist/interface.d.ts +17 -6
- package/dist/plugins/index.d.ts +1 -0
- package/dist/plugins/two-factor.d.ts +16 -0
- package/dist/plugins.js +27 -0
- package/dist/providers/default-credentials.d.ts +11 -0
- package/dist/providers/default-credentials.js +14 -0
- package/dist/providers/index.d.ts +5 -0
- package/dist/providers/index.js +7 -0
- package/dist/providers.js +6 -0
- package/package.json +11 -3
- package/src/auth.ts +141 -0
- package/src/components/RedirectLogin/index.ts +3 -4
- package/src/core.ts +143 -64
- package/src/helper.ts +1 -15
- package/src/index.ts +23 -75
- package/src/interface.ts +19 -6
- package/src/plugins/index.ts +1 -0
- package/src/plugins/two-factor.ts +49 -0
- package/src/providers/default-credentials.ts +29 -0
- package/src/providers/index.ts +5 -0
- package/dist/context.d.ts +0 -2
- package/src/context.ts +0 -4
package/dist/interface.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { RouteLocationRaw } from 'vue-router';
|
|
2
|
+
import type { CreateAuthOptions } from './core';
|
|
2
3
|
export type Recordable = Record<string, any>;
|
|
3
4
|
export type Fn<T = any, K = any> = (params?: Recordable & T) => Promise<K> | K;
|
|
4
5
|
export type FnApi<T = any, R = any> = (params: Recordable & T, baseURL: string) => Promise<R>;
|
|
5
|
-
export interface AuthOptions {
|
|
6
|
+
export interface AuthOptions<Plugins extends PluginOptions[]> {
|
|
6
7
|
/** 登录后默认重定向至 */
|
|
7
8
|
redirectTo?: RouteLocationRaw | Fn;
|
|
8
9
|
/** 页面配置 */
|
|
@@ -12,12 +13,22 @@ export interface AuthOptions {
|
|
|
12
13
|
};
|
|
13
14
|
/** 接口的baseURL */
|
|
14
15
|
baseURL: string;
|
|
15
|
-
providers?:
|
|
16
|
+
providers?: CreateAuthOptions<Plugins>['providers'];
|
|
17
|
+
plugins?: CreateAuthOptions<Plugins>['plugins'];
|
|
16
18
|
}
|
|
17
|
-
export interface
|
|
18
|
-
/**
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
export interface CreateAuthModule {
|
|
20
|
+
/** 登录后默认重定向至 */
|
|
21
|
+
redirectTo?: RouteLocationRaw | Fn;
|
|
22
|
+
/** 页面配置 */
|
|
23
|
+
pages?: {
|
|
24
|
+
/** 默认登录页 */
|
|
25
|
+
signIn?: RouteLocationRaw;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
export interface PluginOptions<Extend = any> {
|
|
29
|
+
/** 唯一值 */
|
|
30
|
+
id: string;
|
|
31
|
+
extend?: (context: any) => Extend;
|
|
21
32
|
}
|
|
22
33
|
/** 第三方类型 */
|
|
23
34
|
export type ThirdParty = string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './two-factor';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { RequestInstance } from 'pubinfo-pr';
|
|
2
|
+
import type { Fn, PluginOptions } from '../interface';
|
|
3
|
+
interface TwoFactorExtend {
|
|
4
|
+
twoFactor: {
|
|
5
|
+
sendOtp: Fn;
|
|
6
|
+
verifyOtp: Fn<{
|
|
7
|
+
code: string;
|
|
8
|
+
}>;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export interface TwoFactorOptions {
|
|
12
|
+
/** 请求实例 */
|
|
13
|
+
request: RequestInstance;
|
|
14
|
+
}
|
|
15
|
+
export declare function twoFactor(options: TwoFactorOptions): PluginOptions<TwoFactorExtend>;
|
|
16
|
+
export {};
|
package/dist/plugins.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
function twoFactor(e) {
|
|
2
|
+
let { request: t } = e;
|
|
3
|
+
return {
|
|
4
|
+
id: "two-factor",
|
|
5
|
+
extend() {
|
|
6
|
+
return { twoFactor: {
|
|
7
|
+
sendOtp(e) {
|
|
8
|
+
return t.Post("/auth/2fa/prepare", {
|
|
9
|
+
fa2Type: "sms",
|
|
10
|
+
login2faCode: void 0,
|
|
11
|
+
...e
|
|
12
|
+
});
|
|
13
|
+
},
|
|
14
|
+
verifyOtp(e) {
|
|
15
|
+
let { code: n, ...r } = e ?? {};
|
|
16
|
+
return t.Post("/auth/2fa/verify", {
|
|
17
|
+
fa2Type: "sms",
|
|
18
|
+
login2faCode: void 0,
|
|
19
|
+
verifyCode: n,
|
|
20
|
+
...r
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
} };
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
export { twoFactor };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ProviderOptions, ProviderUserOptions } from '../interface';
|
|
2
|
+
export interface DefaultCredentialsOptions extends ProviderUserOptions {
|
|
3
|
+
}
|
|
4
|
+
/**
|
|
5
|
+
* `默认登录`
|
|
6
|
+
*
|
|
7
|
+
* 底座自带的用户名密码登录
|
|
8
|
+
*
|
|
9
|
+
* 默认优先使用 `/auth/loginNew` 接口,若登录参数不符合则调用 `/auth/login` 接口
|
|
10
|
+
*/
|
|
11
|
+
export default function DefaultCredentials(options?: DefaultCredentialsOptions): ProviderOptions;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { useUserStore } from "pubinfo-pr";
|
|
2
|
+
function DefaultCredentials(e) {
|
|
3
|
+
return {
|
|
4
|
+
id: "default-credentials",
|
|
5
|
+
name: "默认登录",
|
|
6
|
+
type: "custom",
|
|
7
|
+
signIn: async (e) => {
|
|
8
|
+
let t = useUserStore();
|
|
9
|
+
return await (e.captchaType ? t.signIn : t.login)(e);
|
|
10
|
+
},
|
|
11
|
+
...e
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export { DefaultCredentials as default };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import FourA from "./4A.js";
|
|
2
|
+
import Credentials from "./credentials.js";
|
|
3
|
+
import DefaultCredentials from "./default-credentials.js";
|
|
4
|
+
import DingZJ from "./ding-zj.js";
|
|
5
|
+
import Sso from "./sso.js";
|
|
6
|
+
import "../providers.js";
|
|
7
|
+
export { Credentials, DefaultCredentials, DingZJ, FourA, Sso };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import FourA from "./providers/4A.js";
|
|
2
|
+
import Credentials from "./providers/credentials.js";
|
|
3
|
+
import DefaultCredentials from "./providers/default-credentials.js";
|
|
4
|
+
import DingZJ from "./providers/ding-zj.js";
|
|
5
|
+
import Sso from "./providers/sso.js";
|
|
6
|
+
export { Credentials, DefaultCredentials, DingZJ, FourA, Sso };
|
package/package.json
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pubinfo-pr/module-auth",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.203.
|
|
4
|
+
"version": "0.203.2",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
8
8
|
"default": "./dist/index.js"
|
|
9
9
|
},
|
|
10
|
+
"./providers": {
|
|
11
|
+
"types": "./dist/providers/index.d.ts",
|
|
12
|
+
"default": "./dist/providers/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./plugins": {
|
|
15
|
+
"types": "./dist/plugins/index.d.ts",
|
|
16
|
+
"default": "./dist/plugins.js"
|
|
17
|
+
},
|
|
10
18
|
"./providers/*": {
|
|
11
19
|
"types": "./dist/providers/*.d.ts",
|
|
12
20
|
"default": "./dist/providers/*.js"
|
|
@@ -23,10 +31,10 @@
|
|
|
23
31
|
"node": "^20.19.0 || >=22.12.0"
|
|
24
32
|
},
|
|
25
33
|
"peerDependencies": {
|
|
26
|
-
"pubinfo-pr": "0.203.
|
|
34
|
+
"pubinfo-pr": "0.203.2"
|
|
27
35
|
},
|
|
28
36
|
"devDependencies": {
|
|
29
|
-
"pubinfo-pr": "0.203.
|
|
37
|
+
"pubinfo-pr": "0.203.2"
|
|
30
38
|
},
|
|
31
39
|
"scripts": {
|
|
32
40
|
"dev": "pubinfo build --watch",
|
package/src/auth.ts
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import type { ModuleOptions } from 'pubinfo-pr';
|
|
2
|
+
import type { RouteRecordRaw } from 'vue-router';
|
|
3
|
+
import type { AuthClient as AuthClientInstance } from './core';
|
|
4
|
+
import type { AuthOptions, CreateAuthModule, PluginOptions } from './interface';
|
|
5
|
+
import { cleanup } from 'pubinfo-pr';
|
|
6
|
+
import { createAuth } from './core';
|
|
7
|
+
import { PageAuth } from './pages/auth';
|
|
8
|
+
|
|
9
|
+
let authClient!: AuthClientInstance;
|
|
10
|
+
|
|
11
|
+
export const AuthClient: AuthClientInstance = {
|
|
12
|
+
signIn: (...args) => authClient.signIn(...args),
|
|
13
|
+
authenticate: (...args) => authClient.authenticate(...args),
|
|
14
|
+
renderQRCode: (...args) => authClient.renderQRCode(...args),
|
|
15
|
+
redirect: (...args) => authClient.redirect(...args),
|
|
16
|
+
getProvider: (...args) => authClient.getProvider(...args),
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @deprecated 请使用 `createAuthModule` 和 `createAuth` 替换
|
|
21
|
+
*/
|
|
22
|
+
export function auth<Plugins extends PluginOptions[]>(options: AuthOptions<Plugins>): ModuleOptions {
|
|
23
|
+
const {
|
|
24
|
+
redirectTo = '/',
|
|
25
|
+
pages = {},
|
|
26
|
+
baseURL,
|
|
27
|
+
providers,
|
|
28
|
+
plugins,
|
|
29
|
+
} = options;
|
|
30
|
+
const { signIn = '/login' } = pages;
|
|
31
|
+
|
|
32
|
+
authClient = createAuth<Plugins>({
|
|
33
|
+
baseURL,
|
|
34
|
+
providers,
|
|
35
|
+
plugins,
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
return {
|
|
39
|
+
name: 'pubinfo-pr:auth',
|
|
40
|
+
enforce: 'pre',
|
|
41
|
+
setup(ctx) {
|
|
42
|
+
const { router } = ctx;
|
|
43
|
+
|
|
44
|
+
const ROUTE_AUTH: RouteRecordRaw = {
|
|
45
|
+
path: '/auth/:type',
|
|
46
|
+
name: 'Auth',
|
|
47
|
+
component: PageAuth,
|
|
48
|
+
meta: {
|
|
49
|
+
whiteList: true,
|
|
50
|
+
title: '授权登录',
|
|
51
|
+
},
|
|
52
|
+
props: route => ({
|
|
53
|
+
type: route.params.type,
|
|
54
|
+
authenticate: authClient.authenticate,
|
|
55
|
+
redirectTo() {
|
|
56
|
+
if (typeof redirectTo === 'function') {
|
|
57
|
+
redirectTo();
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
router.push(redirectTo);
|
|
62
|
+
},
|
|
63
|
+
}),
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
router.beforeEach((to) => {
|
|
67
|
+
// 注册静态页面
|
|
68
|
+
if (!router.hasRoute(ROUTE_AUTH.name!)) {
|
|
69
|
+
router.addRoute(ROUTE_AUTH);
|
|
70
|
+
return to.fullPath;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// 前往单点登录前,清空登录状态
|
|
74
|
+
if (to.name === ROUTE_AUTH.name) {
|
|
75
|
+
cleanup();
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// 前往登录前,重定向至统一登录页(若有)
|
|
79
|
+
if (to.path === signIn) {
|
|
80
|
+
authClient.redirect();
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function createAuthModule(authClient: AuthClientInstance, options: CreateAuthModule = {}): ModuleOptions {
|
|
88
|
+
const {
|
|
89
|
+
redirectTo = '/',
|
|
90
|
+
pages = {},
|
|
91
|
+
} = options;
|
|
92
|
+
const { signIn = '/login' } = pages;
|
|
93
|
+
|
|
94
|
+
return {
|
|
95
|
+
name: 'pubinfo-pr:auth',
|
|
96
|
+
enforce: 'pre',
|
|
97
|
+
setup(ctx) {
|
|
98
|
+
const { router } = ctx;
|
|
99
|
+
|
|
100
|
+
const ROUTE_AUTH: RouteRecordRaw = {
|
|
101
|
+
path: '/auth/:type',
|
|
102
|
+
name: 'Auth',
|
|
103
|
+
component: PageAuth,
|
|
104
|
+
meta: {
|
|
105
|
+
whiteList: true,
|
|
106
|
+
title: '授权登录',
|
|
107
|
+
},
|
|
108
|
+
props: route => ({
|
|
109
|
+
type: route.params.type,
|
|
110
|
+
authenticate: authClient.authenticate,
|
|
111
|
+
redirectTo() {
|
|
112
|
+
if (typeof redirectTo === 'function') {
|
|
113
|
+
redirectTo();
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
router.push(redirectTo);
|
|
118
|
+
},
|
|
119
|
+
}),
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
router.beforeEach((to) => {
|
|
123
|
+
// 注册静态页面
|
|
124
|
+
if (!router.hasRoute(ROUTE_AUTH.name!)) {
|
|
125
|
+
router.addRoute(ROUTE_AUTH);
|
|
126
|
+
return to.fullPath;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// 前往单点登录前,清空登录状态
|
|
130
|
+
if (to.name === ROUTE_AUTH.name) {
|
|
131
|
+
cleanup();
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// 前往登录前,重定向至统一登录页(若有)
|
|
135
|
+
if (to.path === signIn) {
|
|
136
|
+
authClient.redirect();
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
},
|
|
140
|
+
};
|
|
141
|
+
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { defineComponent, h } from 'vue';
|
|
2
|
-
import {
|
|
3
|
-
import { getProvider } from '@/helper';
|
|
2
|
+
import { AuthClient } from '@/auth';
|
|
4
3
|
|
|
5
4
|
export const RedirectLogin = defineComponent({
|
|
6
5
|
name: 'RedirectLogin',
|
|
@@ -10,7 +9,7 @@ export const RedirectLogin = defineComponent({
|
|
|
10
9
|
color: String,
|
|
11
10
|
},
|
|
12
11
|
setup(props) {
|
|
13
|
-
const provider = getProvider(props.id);
|
|
12
|
+
const provider = AuthClient.getProvider(props.id);
|
|
14
13
|
return () => {
|
|
15
14
|
return h('div', [
|
|
16
15
|
h(
|
|
@@ -33,7 +32,7 @@ export const RedirectLogin = defineComponent({
|
|
|
33
32
|
letterSpacing: '0.1em',
|
|
34
33
|
backgroundColor: props.color,
|
|
35
34
|
},
|
|
36
|
-
onClick: () => signIn(provider.id),
|
|
35
|
+
onClick: () => AuthClient.signIn(provider.id),
|
|
37
36
|
},
|
|
38
37
|
`前往${provider.name}`,
|
|
39
38
|
),
|
package/src/core.ts
CHANGED
|
@@ -1,75 +1,154 @@
|
|
|
1
|
-
import type { Recordable, ThirdParty } from './interface';
|
|
2
|
-
import {
|
|
3
|
-
import { createUrl, createUrlByProvider, getProvider } from './helper';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* 前往登录
|
|
7
|
-
* @param id 唯一值
|
|
8
|
-
* @param options 登录时需要传递的参数
|
|
9
|
-
*/
|
|
10
|
-
export async function signIn(id: ThirdParty, options?: Recordable) {
|
|
11
|
-
const provider = getProvider(id);
|
|
12
|
-
|
|
13
|
-
if (typeof provider.signIn === 'function') {
|
|
14
|
-
return await provider.signIn(options);
|
|
15
|
-
}
|
|
1
|
+
import type { PluginOptions, ProviderOptions, Recordable, ThirdParty } from './interface';
|
|
2
|
+
import { createUrl, createUrlByProvider } from './helper';
|
|
16
3
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
4
|
+
export interface CreateAuthOptions<Plugins extends PluginOptions[]> {
|
|
5
|
+
baseURL: string
|
|
6
|
+
providers?: ProviderOptions[]
|
|
7
|
+
plugins?: Plugins
|
|
21
8
|
}
|
|
22
9
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
10
|
+
export interface AuthClient {
|
|
11
|
+
/**
|
|
12
|
+
* 前往登录
|
|
13
|
+
* @param id 唯一值
|
|
14
|
+
* @param options 登录时需要传递的参数
|
|
15
|
+
*/
|
|
16
|
+
signIn: (id: ThirdParty, options?: Recordable) => Promise<any> | any
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* 生成二维码
|
|
20
|
+
* @param id 第三方的唯一值
|
|
21
|
+
* @param options 生成二维码需要传递的参数
|
|
22
|
+
* @param options.id `getElementById`中指定的`id`
|
|
23
|
+
*/
|
|
24
|
+
renderQRCode: (id: ThirdParty, options: { id: string } & Recordable) => void
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* 认证
|
|
28
|
+
* @param id 第三方的唯一值
|
|
29
|
+
*/
|
|
30
|
+
authenticate: (id: ThirdParty) => Promise<any>
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* 重定向至统一登录页
|
|
34
|
+
*/
|
|
35
|
+
redirect: () => void
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* 获取指定的 `Provider`
|
|
39
|
+
* @param id
|
|
40
|
+
*/
|
|
41
|
+
getProvider: (id?: ThirdParty) => ProviderOptions
|
|
36
42
|
}
|
|
37
43
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const params = new URLSearchParams(qs);
|
|
50
|
-
const paramsObject = Object.fromEntries(params.entries());
|
|
51
|
-
|
|
52
|
-
if (typeof provider.authenticate === 'function') {
|
|
53
|
-
return await provider.authenticate(paramsObject, baseURL);
|
|
54
|
-
}
|
|
44
|
+
type UnionToIntersection<U>
|
|
45
|
+
= (U extends any ? (x: U) => any : never) extends (x: infer I) => any
|
|
46
|
+
? I
|
|
47
|
+
: never;
|
|
48
|
+
|
|
49
|
+
type PluginExtend<P extends PluginOptions[]>
|
|
50
|
+
= UnionToIntersection<
|
|
51
|
+
{
|
|
52
|
+
[K in keyof P]: P[K] extends PluginOptions<infer E> ? E : never
|
|
53
|
+
}[number]
|
|
54
|
+
>;
|
|
55
55
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
56
|
+
export function createAuth<Plugins extends PluginOptions[]>(options: CreateAuthOptions<Plugins>): AuthClient & PluginExtend<Plugins> {
|
|
57
|
+
const { baseURL, providers = [], plugins = [] } = options;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* 获取指定的 `Provider`
|
|
61
|
+
* @param id
|
|
62
|
+
*/
|
|
63
|
+
function getProvider(id?: ThirdParty) {
|
|
64
|
+
const provider = id ? providers?.find(provider => provider.id === id) : providers?.[0];
|
|
65
|
+
if (!provider) {
|
|
66
|
+
throw new Error(`Provider '${id}' is not found.`);
|
|
67
|
+
}
|
|
68
|
+
return provider;
|
|
60
69
|
}
|
|
61
|
-
}
|
|
62
70
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
+
const authClient = {
|
|
72
|
+
/**
|
|
73
|
+
* 前往登录
|
|
74
|
+
* @param id 唯一值
|
|
75
|
+
* @param options 登录时需要传递的参数
|
|
76
|
+
*/
|
|
77
|
+
async signIn(id: ThirdParty, options?: Recordable) {
|
|
78
|
+
const provider = getProvider(id);
|
|
79
|
+
|
|
80
|
+
if (typeof provider.signIn === 'function') {
|
|
81
|
+
return await provider.signIn(options);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (['oauth', 'custom'].includes(provider.type)) {
|
|
85
|
+
const url = createUrlByProvider(provider);
|
|
86
|
+
window.location.replace(url);
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* 生成二维码
|
|
92
|
+
* @param id 第三方的唯一值
|
|
93
|
+
* @param options 生成二维码需要传递的参数
|
|
94
|
+
* @param options.id `getElementById`中指定的`id`
|
|
95
|
+
*/
|
|
96
|
+
renderQRCode(id: ThirdParty, options: { id: string } & Recordable) {
|
|
97
|
+
const provider = getProvider(id);
|
|
98
|
+
|
|
99
|
+
if (['oauth', 'custom'].includes(provider.type)) {
|
|
100
|
+
const url = createUrlByProvider(provider);
|
|
101
|
+
provider.initQRCode?.(url, options);
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* 认证
|
|
107
|
+
* @param id 第三方的唯一值
|
|
108
|
+
*/
|
|
109
|
+
async authenticate(id: ThirdParty) {
|
|
110
|
+
const provider = getProvider(id);
|
|
111
|
+
|
|
112
|
+
// TODO 处理hash路由中的#
|
|
113
|
+
// 获取URL上的参数
|
|
114
|
+
const qs = window.location.href.split('?')?.[1] ?? '';
|
|
115
|
+
const params = new URLSearchParams(qs);
|
|
116
|
+
const paramsObject = Object.fromEntries(params.entries());
|
|
117
|
+
|
|
118
|
+
if (typeof provider.authenticate === 'function') {
|
|
119
|
+
return await provider.authenticate(paramsObject, baseURL);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (['oauth', 'cas', 'custom'].includes(provider.type)) {
|
|
123
|
+
const url = createUrl(`${baseURL}${provider.authenticate}`, paramsObject);
|
|
124
|
+
const response = await fetch(url);
|
|
125
|
+
return await response.json();
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* 重定向至统一登录页
|
|
131
|
+
*/
|
|
132
|
+
redirect() {
|
|
133
|
+
const provider = providers?.find(provider => provider.type === 'cas');
|
|
134
|
+
if (!provider) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const url = createUrlByProvider(provider);
|
|
139
|
+
window.location.replace(url);
|
|
140
|
+
},
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* 获取指定的 `Provider`
|
|
144
|
+
* @param id
|
|
145
|
+
*/
|
|
146
|
+
getProvider,
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
for (const plugin of plugins) {
|
|
150
|
+
Object.assign(authClient, plugin.extend?.({}));
|
|
71
151
|
}
|
|
72
152
|
|
|
73
|
-
|
|
74
|
-
window.location.replace(url);
|
|
153
|
+
return authClient as AuthClient & PluginExtend<Plugins>;
|
|
75
154
|
}
|
package/src/helper.ts
CHANGED
|
@@ -1,18 +1,4 @@
|
|
|
1
|
-
import type { ProviderUserOptions, Recordable
|
|
2
|
-
import { ctx } from './context';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* 获取指定的 `Provider`
|
|
6
|
-
* @param id
|
|
7
|
-
*/
|
|
8
|
-
export function getProvider(id?: ThirdParty) {
|
|
9
|
-
const { providers } = ctx.use();
|
|
10
|
-
const provider = id ? providers?.find(provider => provider.id === id) : providers?.[0];
|
|
11
|
-
if (!provider) {
|
|
12
|
-
throw new Error(`Provider '${id}' is not found.`);
|
|
13
|
-
}
|
|
14
|
-
return provider;
|
|
15
|
-
}
|
|
1
|
+
import type { ProviderUserOptions, Recordable } from './interface';
|
|
16
2
|
|
|
17
3
|
/**
|
|
18
4
|
* 构建第三方授权登录地址
|
package/src/index.ts
CHANGED
|
@@ -1,78 +1,26 @@
|
|
|
1
|
-
import
|
|
2
|
-
import type { RouteRecordRaw } from 'vue-router';
|
|
3
|
-
import type { AuthOptions } from './interface';
|
|
4
|
-
import { cleanup } from 'pubinfo-pr';
|
|
5
|
-
import { ctx } from './context';
|
|
6
|
-
import { authenticate, redirect } from './core';
|
|
7
|
-
import { PageAuth } from './pages/auth';
|
|
8
|
-
|
|
9
|
-
export function auth(options: AuthOptions): ModuleOptions {
|
|
10
|
-
const {
|
|
11
|
-
redirectTo = '/',
|
|
12
|
-
pages = {},
|
|
13
|
-
baseURL,
|
|
14
|
-
providers,
|
|
15
|
-
} = options;
|
|
16
|
-
const { signIn = '/login' } = pages;
|
|
17
|
-
|
|
18
|
-
ctx.set({ baseURL, providers });
|
|
19
|
-
|
|
20
|
-
return {
|
|
21
|
-
name: 'pubinfo-pr:auth',
|
|
22
|
-
enforce: 'pre',
|
|
23
|
-
setup(ctx) {
|
|
24
|
-
const { router } = ctx;
|
|
25
|
-
|
|
26
|
-
const ROUTE_AUTH: RouteRecordRaw = {
|
|
27
|
-
path: '/auth/:type',
|
|
28
|
-
name: 'Auth',
|
|
29
|
-
component: PageAuth,
|
|
30
|
-
meta: {
|
|
31
|
-
whiteList: true,
|
|
32
|
-
title: '授权登录',
|
|
33
|
-
},
|
|
34
|
-
props: route => ({
|
|
35
|
-
type: route.params.type,
|
|
36
|
-
authenticate,
|
|
37
|
-
redirectTo() {
|
|
38
|
-
if (typeof redirectTo === 'function') {
|
|
39
|
-
redirectTo();
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
router.push(redirectTo);
|
|
44
|
-
},
|
|
45
|
-
}),
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
router.beforeEach((to) => {
|
|
49
|
-
// 注册静态页面
|
|
50
|
-
if (!router.hasRoute(ROUTE_AUTH.name!)) {
|
|
51
|
-
router.addRoute(ROUTE_AUTH);
|
|
52
|
-
return to.fullPath;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// 前往单点登录前,清空登录状态
|
|
56
|
-
if (to.name === ROUTE_AUTH.name) {
|
|
57
|
-
cleanup();
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// 前往登录前,重定向至统一登录页(若有)
|
|
61
|
-
if (to.path === signIn) {
|
|
62
|
-
redirect();
|
|
63
|
-
}
|
|
64
|
-
});
|
|
65
|
-
},
|
|
66
|
-
};
|
|
67
|
-
}
|
|
1
|
+
import { AuthClient } from './auth';
|
|
68
2
|
|
|
3
|
+
export * from './auth';
|
|
69
4
|
export { LoginWithFourA } from './components/LoginWithFourA';
|
|
70
|
-
|
|
71
|
-
export {
|
|
72
|
-
authenticate,
|
|
73
|
-
redirect,
|
|
74
|
-
renderQRCode,
|
|
75
|
-
signIn,
|
|
76
|
-
} from './core';
|
|
77
|
-
|
|
5
|
+
export { createAuth } from './core';
|
|
78
6
|
export * from './interface';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @deprecated 认证, 请使用 `AuthClient.authenticate` 方法替代
|
|
10
|
+
*/
|
|
11
|
+
export const authenticate = AuthClient.authenticate;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @deprecated 重定向至统一登录页, 请使用 `AuthClient.redirect` 方法替代
|
|
15
|
+
*/
|
|
16
|
+
export const redirect = AuthClient.redirect;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @deprecated 生成二维码, 请使用 `AuthClient.renderQRCode` 方法替代
|
|
20
|
+
*/
|
|
21
|
+
export const renderQRCode = AuthClient.renderQRCode;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @deprecated 前往登录, 请使用 `AuthClient.signIn` 方法替代
|
|
25
|
+
*/
|
|
26
|
+
export const signIn = AuthClient.signIn;
|