@authing/guard-shim-react18 5.0.8-alpha.2 → 5.0.8-alpha.4
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/esm/guard.min.css +2 -0
- package/dist/esm/guard.min.js +2 -0
- package/dist/esm/guard.min.js.LICENSE.txt +29 -0
- package/dist/typings/index.d.ts +45 -0
- package/dist/typings/types.d.ts +47 -0
- package/package.json +15 -8
- package/src/index.tsx +0 -515
- package/src/types.ts +0 -93
- package/tsconfig.json +0 -31
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license React
|
|
3
|
+
* react-dom.production.min.js
|
|
4
|
+
*
|
|
5
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
6
|
+
*
|
|
7
|
+
* This source code is licensed under the MIT license found in the
|
|
8
|
+
* LICENSE file in the root directory of this source tree.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @license React
|
|
13
|
+
* react.production.min.js
|
|
14
|
+
*
|
|
15
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
16
|
+
*
|
|
17
|
+
* This source code is licensed under the MIT license found in the
|
|
18
|
+
* LICENSE file in the root directory of this source tree.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @license React
|
|
23
|
+
* scheduler.production.min.js
|
|
24
|
+
*
|
|
25
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
26
|
+
*
|
|
27
|
+
* This source code is licensed under the MIT license found in the
|
|
28
|
+
* LICENSE file in the root directory of this source tree.
|
|
29
|
+
*/
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { GuardOptions, GuardEventsKebabToCamelType, StartWithRedirectOptions, AuthenticationClient, JwtTokenStatus, User, Lang } from './types';
|
|
2
|
+
import '@authing/react18-components/lib/index.min.css';
|
|
3
|
+
export * from './types';
|
|
4
|
+
export declare class Guard {
|
|
5
|
+
options: GuardOptions;
|
|
6
|
+
private visible;
|
|
7
|
+
private then;
|
|
8
|
+
private publicConfig?;
|
|
9
|
+
private root?;
|
|
10
|
+
constructor(options: GuardOptions);
|
|
11
|
+
private adaptOptions;
|
|
12
|
+
private getPublicConfig;
|
|
13
|
+
getAuthClient(): Promise<AuthenticationClient>;
|
|
14
|
+
static getGuardContainer(selector?: string | HTMLElement): Element | null;
|
|
15
|
+
private eventListeners;
|
|
16
|
+
/**
|
|
17
|
+
* 启动嵌入模式
|
|
18
|
+
* @param el String
|
|
19
|
+
* @returns Promise
|
|
20
|
+
*/
|
|
21
|
+
start(el?: string): Promise<User>;
|
|
22
|
+
startRegister(): void;
|
|
23
|
+
checkLoginStatus(): Promise<JwtTokenStatus | undefined>;
|
|
24
|
+
changeLang(lang: Lang): void;
|
|
25
|
+
changeContentCSS(contentCSS: string): void;
|
|
26
|
+
/**
|
|
27
|
+
* 启动跳转模式
|
|
28
|
+
*/
|
|
29
|
+
startWithRedirect(options?: StartWithRedirectOptions): Promise<void>;
|
|
30
|
+
handleRedirectCallback(): Promise<void>;
|
|
31
|
+
private getAccessTokenByCode;
|
|
32
|
+
private getCodeAndCodeChallenge;
|
|
33
|
+
private setStorageCache;
|
|
34
|
+
private parseUrlQuery;
|
|
35
|
+
/**
|
|
36
|
+
* 获取当前用户信息
|
|
37
|
+
*/
|
|
38
|
+
trackSession(): Promise<User | null>;
|
|
39
|
+
logout(): Promise<void>;
|
|
40
|
+
render(): Promise<void>;
|
|
41
|
+
on<T extends keyof GuardEventsKebabToCamelType>(evt: T, handler: Exclude<GuardEventsKebabToCamelType[T], undefined>): void;
|
|
42
|
+
show(): void;
|
|
43
|
+
hide(): void;
|
|
44
|
+
unmount(): void;
|
|
45
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { GuardEventsKebabToCamelType, Lang, GuardProps, GuardLocalConfig, CodeAction, ApiCode, GuardModuleType, LoginMethods, OIDCConnectionMode, SocialConnectionProvider, Protocol, RegisterMethods, GuardMode, InputMethod, GuardPageSene, EmailScene, SceneType } from '@authing/react18-components';
|
|
2
|
+
export declare type ICodeAction = `${CodeAction}`;
|
|
3
|
+
export declare type IApiCode = `${ApiCode}`;
|
|
4
|
+
export declare type IGuardModuleType = `${GuardModuleType}`;
|
|
5
|
+
export declare type ILoginMethod = `${LoginMethods}`;
|
|
6
|
+
export declare type IOIDCConnectionMode = `${OIDCConnectionMode}`;
|
|
7
|
+
export declare type ISocialConnectionProvider = `${SocialConnectionProvider}`;
|
|
8
|
+
export declare type IProtocol = `${Protocol}`;
|
|
9
|
+
export declare type IRegisterMethod = `${RegisterMethods}`;
|
|
10
|
+
export declare type IGuardMode = `${GuardMode}`;
|
|
11
|
+
export declare type IInputMethod = `${InputMethod}`;
|
|
12
|
+
export declare type IGuardPageSene = `${GuardPageSene}`;
|
|
13
|
+
export declare type IEmailScene = `${EmailScene}`;
|
|
14
|
+
export declare type ISceneType = `${SceneType}`;
|
|
15
|
+
export declare type GuardEventListeners = {
|
|
16
|
+
[key in keyof GuardEventsKebabToCamelType]: Exclude<Required<GuardEventsKebabToCamelType>[key], undefined>[];
|
|
17
|
+
};
|
|
18
|
+
export declare type CodeChallengeMethod = 'S256' | 'plain';
|
|
19
|
+
export interface IGuardConfig extends GuardLocalConfig {
|
|
20
|
+
socialConnectionList?: ISocialConnectionProvider[];
|
|
21
|
+
loginMethod?: ILoginMethod;
|
|
22
|
+
loginMethodList: ILoginMethod[];
|
|
23
|
+
registerMethod?: IRegisterMethod;
|
|
24
|
+
registerMethodList?: IRegisterMethod[];
|
|
25
|
+
contentCSS?: string;
|
|
26
|
+
}
|
|
27
|
+
export interface GuardOptions extends GuardProps {
|
|
28
|
+
appId: string;
|
|
29
|
+
host?: string;
|
|
30
|
+
redirectUri?: string;
|
|
31
|
+
mode?: IGuardMode;
|
|
32
|
+
defaultScene?: IGuardModuleType;
|
|
33
|
+
tenantId?: string;
|
|
34
|
+
lang?: Lang;
|
|
35
|
+
isSSO?: boolean;
|
|
36
|
+
config?: Partial<IGuardConfig>;
|
|
37
|
+
}
|
|
38
|
+
export interface StartWithRedirectOptions {
|
|
39
|
+
codeChallengeMethod?: CodeChallengeMethod;
|
|
40
|
+
scope?: string;
|
|
41
|
+
redirectUri?: string;
|
|
42
|
+
state?: string;
|
|
43
|
+
responseType?: 'code' | 'code id_token token' | 'code id_token' | 'code token' | 'id_token token' | 'id_token' | 'none';
|
|
44
|
+
responseMode?: 'query' | 'fragment' | 'form_post';
|
|
45
|
+
nonce?: string;
|
|
46
|
+
}
|
|
47
|
+
export * from '@authing/react18-components';
|
package/package.json
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@authing/guard-shim-react18",
|
|
3
|
-
"version": "5.0.8-alpha.
|
|
3
|
+
"version": "5.0.8-alpha.4",
|
|
4
4
|
"description": "Guard shim for react18",
|
|
5
|
-
"
|
|
5
|
+
"module": "dist/esm/guard.min.js",
|
|
6
|
+
"types": "dist/typings/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist"
|
|
9
|
+
],
|
|
6
10
|
"scripts": {
|
|
7
11
|
"autoinstall": "npm ci",
|
|
8
|
-
"build": "
|
|
12
|
+
"build": "node scripts/build.js",
|
|
9
13
|
"lint": "eslint --ext .ts,.tsx src/**",
|
|
10
14
|
"lint:fix": "eslint --fix --ext .ts,.tsx src/**",
|
|
11
15
|
"release:official": "npm publish --verbose --access public",
|
|
@@ -13,15 +17,18 @@
|
|
|
13
17
|
},
|
|
14
18
|
"devDependencies": {
|
|
15
19
|
"@types/react": "^17.0.43",
|
|
16
|
-
"@types/react-dom": "^17.0.14"
|
|
20
|
+
"@types/react-dom": "^17.0.14",
|
|
21
|
+
"css-loader": "^6.7.1",
|
|
22
|
+
"mini-css-extract-plugin": "^2.6.1",
|
|
23
|
+
"rimraf": "^2.6.2",
|
|
24
|
+
"ts-loader": "^9.3.1",
|
|
25
|
+
"webpack": "^5.72.0"
|
|
17
26
|
},
|
|
18
|
-
"
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@authing/react18-components": "^4.1.0-alpha.0",
|
|
19
29
|
"react": "^18.0.0",
|
|
20
30
|
"react-dom": "^18.0.0"
|
|
21
31
|
},
|
|
22
|
-
"dependencies": {
|
|
23
|
-
"@authing/react18-components": "^4.1.0-alpha.0"
|
|
24
|
-
},
|
|
25
32
|
"author": "https://github.com/authing",
|
|
26
33
|
"license": "MIT",
|
|
27
34
|
"publishConfig": {
|
package/src/index.tsx
DELETED
|
@@ -1,515 +0,0 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
|
-
|
|
3
|
-
import { createRoot, Root } from 'react-dom/client'
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
GuardOptions,
|
|
7
|
-
GuardMode,
|
|
8
|
-
GuardEventsCamelToKebabMapping,
|
|
9
|
-
GuardLocalConfig,
|
|
10
|
-
GuardEventListeners,
|
|
11
|
-
GuardEvents,
|
|
12
|
-
Guard as ReactAuthingGuard,
|
|
13
|
-
GuardEventsKebabToCamelType,
|
|
14
|
-
StartWithRedirectOptions,
|
|
15
|
-
AuthenticationClient,
|
|
16
|
-
JwtTokenStatus,
|
|
17
|
-
User,
|
|
18
|
-
GuardModuleType,
|
|
19
|
-
Lang,
|
|
20
|
-
IGuardConfig
|
|
21
|
-
} from './types'
|
|
22
|
-
|
|
23
|
-
import '@authing/react18-components/lib/index.min.css'
|
|
24
|
-
|
|
25
|
-
export * from './types'
|
|
26
|
-
|
|
27
|
-
const isDef = (value: unknown) => value !== undefined
|
|
28
|
-
|
|
29
|
-
export class Guard {
|
|
30
|
-
public options: GuardOptions
|
|
31
|
-
|
|
32
|
-
private visible = false
|
|
33
|
-
|
|
34
|
-
private then: () => Promise<any | never>
|
|
35
|
-
|
|
36
|
-
private publicConfig?: Record<string, unknown>
|
|
37
|
-
|
|
38
|
-
private root?: Root
|
|
39
|
-
|
|
40
|
-
constructor(options: GuardOptions) {
|
|
41
|
-
if (!options.appId) {
|
|
42
|
-
throw new Error('appId is required')
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const config = {
|
|
46
|
-
...options.config
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
this.options = this.adaptOptions(options, config)
|
|
50
|
-
|
|
51
|
-
const init = (async () => {
|
|
52
|
-
if (this.publicConfig) {
|
|
53
|
-
return this.publicConfig
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const publicConfigRes = await this.getPublicConfig()
|
|
57
|
-
|
|
58
|
-
return (this.publicConfig = publicConfigRes.data)
|
|
59
|
-
})()
|
|
60
|
-
|
|
61
|
-
this.then = init.then.bind(init)
|
|
62
|
-
|
|
63
|
-
this.visible = !!(options.mode === GuardMode.Modal)
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
private adaptOptions(options: GuardOptions, config: Partial<IGuardConfig>) {
|
|
67
|
-
options.host = options.host || ''
|
|
68
|
-
|
|
69
|
-
if (isDef(options.isSSO)) {
|
|
70
|
-
config.isSSO = options.isSSO
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if (isDef(options.defaultScene)) {
|
|
74
|
-
// @ts-ignore
|
|
75
|
-
config.defaultScenes = options.defaultScene
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
if (isDef(options.lang)) {
|
|
79
|
-
config.lang = options.lang
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
if (isDef(options.host)) {
|
|
83
|
-
config.host = options.host
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
if (isDef(options.mode)) {
|
|
87
|
-
// @ts-ignore
|
|
88
|
-
config.mode = options.mode
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
options.config = config
|
|
92
|
-
|
|
93
|
-
if (isDef(options.config.socialConnectionList)) {
|
|
94
|
-
// @ts-ignore
|
|
95
|
-
options.config.socialConnections = options.config.socialConnectionList
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
if (isDef(options.config.loginMethod)) {
|
|
99
|
-
// @ts-ignore
|
|
100
|
-
options.config.defaultLoginMethod = options.config.loginMethod
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
if (isDef(options.config.loginMethodList)) {
|
|
104
|
-
// @ts-ignore
|
|
105
|
-
options.config.loginMethods = options.config.loginMethodList
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
if (isDef(options.config.registerMethodList)) {
|
|
109
|
-
// @ts-ignore
|
|
110
|
-
options.config.registerMethods = options.config.registerMethodList
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
if (isDef(options.config.registerMethod)) {
|
|
114
|
-
// @ts-ignore
|
|
115
|
-
options.config.defaultRegisterMethod = options.config.registerMethod
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
if (isDef(options.config.contentCSS)) {
|
|
119
|
-
options.config.contentCss = options.config.contentCSS
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
return options
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
private async getPublicConfig(): Promise<{
|
|
126
|
-
[prop: string]: any
|
|
127
|
-
}> {
|
|
128
|
-
const host = `${this.options.host}` || 'https://core.authing.cn'
|
|
129
|
-
|
|
130
|
-
const options: RequestInit = {
|
|
131
|
-
method: 'GET',
|
|
132
|
-
credentials: 'include'
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
const fetchRes = await fetch(
|
|
136
|
-
`${host}/api/v2/applications/${this.options.appId}/public-config`,
|
|
137
|
-
options
|
|
138
|
-
)
|
|
139
|
-
|
|
140
|
-
const publicConfig = await fetchRes.text()
|
|
141
|
-
|
|
142
|
-
return JSON.parse(publicConfig)
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
async getAuthClient(): Promise<AuthenticationClient> {
|
|
146
|
-
let publicConfig = {} as any
|
|
147
|
-
|
|
148
|
-
try {
|
|
149
|
-
publicConfig = await this.then()
|
|
150
|
-
} catch (e) {
|
|
151
|
-
throw new Error(JSON.stringify(e))
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
const _authClientOptions = Object.assign(
|
|
155
|
-
{},
|
|
156
|
-
{
|
|
157
|
-
appId: this.options.appId,
|
|
158
|
-
appHost: this.options.host || `https://${publicConfig.requestHostname}`,
|
|
159
|
-
tenantId: this.options.tenantId,
|
|
160
|
-
redirectUri:
|
|
161
|
-
this.options.redirectUri || publicConfig.oidcConfig.redirect_uris[0],
|
|
162
|
-
tokenEndPointAuthMethod:
|
|
163
|
-
publicConfig.oidcConfig.token_endpoint_auth_method || 'none',
|
|
164
|
-
introspectionEndPointAuthMethod:
|
|
165
|
-
publicConfig.oidcConfig.introspection_endpoint_auth_method || 'none'
|
|
166
|
-
}
|
|
167
|
-
)
|
|
168
|
-
|
|
169
|
-
return new AuthenticationClient(_authClientOptions)
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
static getGuardContainer(selector?: string | HTMLElement): Element | null {
|
|
173
|
-
const defaultId = 'authing_guard_container'
|
|
174
|
-
|
|
175
|
-
if (!selector) {
|
|
176
|
-
let container = document.querySelector(`#${defaultId}`)
|
|
177
|
-
if (!container) {
|
|
178
|
-
container = document.createElement('div')
|
|
179
|
-
container.id = defaultId
|
|
180
|
-
document.body.appendChild(container)
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
return container
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
if (typeof selector === 'string') {
|
|
187
|
-
const res = document.querySelector(selector)
|
|
188
|
-
if (!res) {
|
|
189
|
-
console.warn(
|
|
190
|
-
`Failed to start guard: target selector "${selector}" returned null.`
|
|
191
|
-
)
|
|
192
|
-
}
|
|
193
|
-
return res
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
return selector
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
private eventListeners = Object.values(GuardEventsCamelToKebabMapping).reduce(
|
|
200
|
-
(acc, evtName) => {
|
|
201
|
-
return Object.assign({}, acc, {
|
|
202
|
-
[evtName as string]: []
|
|
203
|
-
})
|
|
204
|
-
},
|
|
205
|
-
{} as GuardEventListeners
|
|
206
|
-
)
|
|
207
|
-
|
|
208
|
-
/**
|
|
209
|
-
* 启动嵌入模式
|
|
210
|
-
* @param el String
|
|
211
|
-
* @returns Promise
|
|
212
|
-
*/
|
|
213
|
-
async start(el?: string): Promise<User> {
|
|
214
|
-
;(this.options.config as Partial<GuardLocalConfig>).target = el
|
|
215
|
-
|
|
216
|
-
this.render()
|
|
217
|
-
|
|
218
|
-
const userInfo = await this.trackSession()
|
|
219
|
-
|
|
220
|
-
if (userInfo) {
|
|
221
|
-
return Promise.resolve(userInfo)
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
return new Promise(resolve => {
|
|
225
|
-
this.on('login', userInfo => {
|
|
226
|
-
resolve(userInfo)
|
|
227
|
-
})
|
|
228
|
-
})
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
startRegister() {
|
|
232
|
-
this.options.defaultScene = GuardModuleType.REGISTER
|
|
233
|
-
|
|
234
|
-
this.options.config = Object.assign({}, this.options.config, {
|
|
235
|
-
defaultScenes: GuardModuleType.REGISTER
|
|
236
|
-
})
|
|
237
|
-
|
|
238
|
-
this.unmount()
|
|
239
|
-
this.render()
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
async checkLoginStatus(): Promise<JwtTokenStatus | undefined> {
|
|
243
|
-
const authClient = await this.getAuthClient()
|
|
244
|
-
const user = await authClient.getCurrentUser()
|
|
245
|
-
|
|
246
|
-
if (!user) {
|
|
247
|
-
return
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
const token = user.token
|
|
251
|
-
|
|
252
|
-
if (!token) {
|
|
253
|
-
return
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
const loginStatus: JwtTokenStatus = await authClient.checkLoginStatus(token)
|
|
257
|
-
|
|
258
|
-
if (loginStatus.status) {
|
|
259
|
-
return loginStatus
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
changeLang(lang: Lang) {
|
|
264
|
-
this.options.lang = lang
|
|
265
|
-
|
|
266
|
-
this.options.config = Object.assign({}, this.options.config, {
|
|
267
|
-
lang
|
|
268
|
-
})
|
|
269
|
-
|
|
270
|
-
this.unmount()
|
|
271
|
-
this.render()
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
changeContentCSS(contentCSS: string) {
|
|
275
|
-
this.options.config = Object.assign({}, this.options.config, {
|
|
276
|
-
contentCss: contentCSS
|
|
277
|
-
})
|
|
278
|
-
|
|
279
|
-
this.unmount()
|
|
280
|
-
this.render()
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
/**
|
|
284
|
-
* 启动跳转模式
|
|
285
|
-
*/
|
|
286
|
-
async startWithRedirect(options: StartWithRedirectOptions = {}) {
|
|
287
|
-
const getRandom = () => Math.random().toString().slice(2)
|
|
288
|
-
|
|
289
|
-
const {
|
|
290
|
-
codeChallengeMethod = 'S256',
|
|
291
|
-
scope = 'openid profile email phone address',
|
|
292
|
-
redirectUri,
|
|
293
|
-
state = getRandom(),
|
|
294
|
-
nonce = getRandom(),
|
|
295
|
-
responseMode = 'query',
|
|
296
|
-
responseType = 'code'
|
|
297
|
-
} = options
|
|
298
|
-
|
|
299
|
-
const authClient = await this.getAuthClient()
|
|
300
|
-
|
|
301
|
-
// 生成一个 code_verifier
|
|
302
|
-
const codeChallenge = authClient.generateCodeChallenge()
|
|
303
|
-
|
|
304
|
-
localStorage.setItem('codeChallenge', codeChallenge)
|
|
305
|
-
|
|
306
|
-
// 计算 code_verifier 的 SHA256 摘要
|
|
307
|
-
const codeChallengeDigest = authClient.getCodeChallengeDigest({
|
|
308
|
-
codeChallenge,
|
|
309
|
-
method: codeChallengeMethod
|
|
310
|
-
})
|
|
311
|
-
|
|
312
|
-
// 构造 OIDC 授权码 + PKCE 模式登录 URL
|
|
313
|
-
const url = authClient.buildAuthorizeUrl({
|
|
314
|
-
codeChallenge: codeChallengeDigest,
|
|
315
|
-
codeChallengeMethod,
|
|
316
|
-
scope,
|
|
317
|
-
redirectUri,
|
|
318
|
-
state,
|
|
319
|
-
nonce,
|
|
320
|
-
responseMode,
|
|
321
|
-
responseType
|
|
322
|
-
})
|
|
323
|
-
|
|
324
|
-
window.location.href = url
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
async handleRedirectCallback() {
|
|
328
|
-
const { code, codeChallenge } = this.getCodeAndCodeChallenge()
|
|
329
|
-
|
|
330
|
-
const { id_token, access_token } = await this.getAccessTokenByCode(
|
|
331
|
-
code,
|
|
332
|
-
codeChallenge
|
|
333
|
-
)
|
|
334
|
-
|
|
335
|
-
const authClient = await this.getAuthClient()
|
|
336
|
-
|
|
337
|
-
const userInfo = await authClient.getUserInfoByAccessToken(access_token)
|
|
338
|
-
|
|
339
|
-
this.setStorageCache(access_token, id_token, userInfo)
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
private async getAccessTokenByCode(code: string, codeChallenge: string) {
|
|
343
|
-
const authClient = await this.getAuthClient()
|
|
344
|
-
|
|
345
|
-
return await authClient.getAccessTokenByCode(code, {
|
|
346
|
-
codeVerifier: codeChallenge
|
|
347
|
-
})
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
private getCodeAndCodeChallenge() {
|
|
351
|
-
const query = this.parseUrlQuery()
|
|
352
|
-
const { code = '' } = query
|
|
353
|
-
const codeChallenge = localStorage.getItem('codeChallenge') || ''
|
|
354
|
-
|
|
355
|
-
return {
|
|
356
|
-
code,
|
|
357
|
-
codeChallenge
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
private setStorageCache(
|
|
362
|
-
accessToken: string,
|
|
363
|
-
idToken: string,
|
|
364
|
-
userInfo: string
|
|
365
|
-
) {
|
|
366
|
-
localStorage.setItem('accessToken', accessToken)
|
|
367
|
-
localStorage.setItem('idToken', idToken)
|
|
368
|
-
localStorage.setItem('userInfo', JSON.stringify(userInfo))
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
private parseUrlQuery() {
|
|
372
|
-
const query: Record<string, string> = {}
|
|
373
|
-
|
|
374
|
-
let queryString = ''
|
|
375
|
-
|
|
376
|
-
try {
|
|
377
|
-
queryString = window.location.search.split('?')[1]
|
|
378
|
-
} catch (e) {
|
|
379
|
-
queryString = window.location.hash.split('#')[1]
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
if (!queryString) {
|
|
383
|
-
return query
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
queryString.split('&').forEach(item => {
|
|
387
|
-
const [key, value] = item.split('=')
|
|
388
|
-
query[key] = value
|
|
389
|
-
})
|
|
390
|
-
|
|
391
|
-
return query
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
/**
|
|
395
|
-
* 获取当前用户信息
|
|
396
|
-
*/
|
|
397
|
-
async trackSession(): Promise<User | null> {
|
|
398
|
-
const authClient = await this.getAuthClient()
|
|
399
|
-
|
|
400
|
-
return authClient.getCurrentUser()
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
async logout() {
|
|
404
|
-
const publicConfig = await this.then()
|
|
405
|
-
|
|
406
|
-
let redirectUri = ''
|
|
407
|
-
|
|
408
|
-
const origin = window.location.origin
|
|
409
|
-
|
|
410
|
-
try {
|
|
411
|
-
redirectUri = publicConfig.logoutRedirectUris[0]
|
|
412
|
-
} catch (e) {
|
|
413
|
-
redirectUri = origin
|
|
414
|
-
} finally {
|
|
415
|
-
if (!redirectUri) {
|
|
416
|
-
redirectUri = origin
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
const idToken = localStorage.getItem('idToken')
|
|
421
|
-
let logoutUrl = ''
|
|
422
|
-
const authClient = await this.getAuthClient()
|
|
423
|
-
|
|
424
|
-
authClient.logout()
|
|
425
|
-
|
|
426
|
-
if (idToken) {
|
|
427
|
-
logoutUrl = authClient.buildLogoutUrl({
|
|
428
|
-
expert: true,
|
|
429
|
-
redirectUri,
|
|
430
|
-
idToken
|
|
431
|
-
})
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
localStorage.clear()
|
|
435
|
-
|
|
436
|
-
window.location.href = logoutUrl || redirectUri
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
async render() {
|
|
440
|
-
const evts: GuardEvents = Object.entries(
|
|
441
|
-
GuardEventsCamelToKebabMapping
|
|
442
|
-
).reduce((acc, [reactEvt, nativeEvt]) => {
|
|
443
|
-
return Object.assign({}, acc, {
|
|
444
|
-
[reactEvt]: (...rest: any) => {
|
|
445
|
-
if (nativeEvt === 'close') {
|
|
446
|
-
this.hide()
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
// TODO 返回最后一个执行函数的值,实际应该只让监听一次
|
|
450
|
-
return (
|
|
451
|
-
(this.eventListeners as any)[nativeEvt as string]
|
|
452
|
-
.map((item: any) => {
|
|
453
|
-
return item(...rest)
|
|
454
|
-
})
|
|
455
|
-
.slice(-1)[0] ?? true
|
|
456
|
-
)
|
|
457
|
-
}
|
|
458
|
-
})
|
|
459
|
-
}, {} as GuardEvents)
|
|
460
|
-
|
|
461
|
-
const publicConfig = await this.then()
|
|
462
|
-
const authClient = await this.getAuthClient()
|
|
463
|
-
|
|
464
|
-
if (this.options.config) {
|
|
465
|
-
this.options.config.host =
|
|
466
|
-
this.options.host || `https://${publicConfig.requestHostname}`
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
const target = Guard.getGuardContainer(this.options.config?.target)
|
|
470
|
-
|
|
471
|
-
if (!target) {
|
|
472
|
-
return
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
const root = (this.root = createRoot(target))
|
|
476
|
-
|
|
477
|
-
return root.render(
|
|
478
|
-
<ReactAuthingGuard
|
|
479
|
-
{...(evts as GuardEvents)}
|
|
480
|
-
appId={this.options.appId}
|
|
481
|
-
tenantId={this.options.tenantId}
|
|
482
|
-
config={this.options.config}
|
|
483
|
-
facePlugin={this.options.facePlugin}
|
|
484
|
-
appendConfig={this.options.appendConfig}
|
|
485
|
-
visible={this.visible}
|
|
486
|
-
authClient={authClient}
|
|
487
|
-
/>
|
|
488
|
-
)
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
on<T extends keyof GuardEventsKebabToCamelType>(
|
|
492
|
-
evt: T,
|
|
493
|
-
handler: Exclude<GuardEventsKebabToCamelType[T], undefined>
|
|
494
|
-
) {
|
|
495
|
-
;(this.eventListeners as any)[evt].push(handler as any)
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
show() {
|
|
499
|
-
this.visible = true
|
|
500
|
-
this.render()
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
hide() {
|
|
504
|
-
this.visible = false
|
|
505
|
-
this.render()
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
unmount() {
|
|
509
|
-
const node = Guard.getGuardContainer(this.options.config?.target)
|
|
510
|
-
|
|
511
|
-
if (node && this.root) {
|
|
512
|
-
this.root.unmount()
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
}
|