@cloudbase/oauth 2.23.3 → 2.24.0
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/cjs/auth/apis.js +170 -14
- package/dist/cjs/auth/auth-error.js +32 -0
- package/dist/cjs/auth/consts.js +24 -2
- package/dist/cjs/auth/models.js +1 -1
- package/dist/cjs/captcha/captcha-dom.js +223 -0
- package/dist/cjs/captcha/captcha.js +11 -102
- package/dist/cjs/index.js +25 -3
- package/dist/cjs/oauth2client/interface.js +1 -1
- package/dist/cjs/oauth2client/models.js +1 -1
- package/dist/cjs/oauth2client/oauth2client.js +384 -110
- package/dist/cjs/utils/base64.js +15 -2
- package/dist/esm/auth/apis.js +113 -2
- package/dist/esm/auth/auth-error.js +9 -0
- package/dist/esm/auth/consts.js +22 -0
- package/dist/esm/captcha/captcha-dom.js +129 -0
- package/dist/esm/captcha/captcha.js +14 -97
- package/dist/esm/index.js +18 -2
- package/dist/esm/oauth2client/oauth2client.js +162 -36
- package/dist/esm/utils/base64.js +12 -0
- package/dist/miniprogram/index.js +1 -1
- package/dist/types/auth/apis.d.ts +19 -1
- package/dist/types/auth/auth-error.d.ts +6 -0
- package/dist/types/auth/consts.d.ts +22 -0
- package/dist/types/auth/models.d.ts +2 -0
- package/dist/types/captcha/captcha-dom.d.ts +3 -0
- package/dist/types/captcha/captcha.d.ts +3 -1
- package/dist/types/index.d.ts +11 -2
- package/dist/types/oauth2client/interface.d.ts +1 -1
- package/dist/types/oauth2client/models.d.ts +14 -0
- package/dist/types/oauth2client/oauth2client.d.ts +58 -2
- package/dist/types/utils/base64.d.ts +5 -0
- package/package.json +4 -4
- package/src/auth/apis.ts +189 -4
- package/src/auth/auth-error.ts +21 -0
- package/src/auth/consts.ts +28 -0
- package/src/auth/models.ts +2 -0
- package/src/captcha/captcha-dom.ts +178 -0
- package/src/captcha/captcha.ts +25 -115
- package/src/index.ts +51 -3
- package/src/oauth2client/interface.ts +1 -1
- package/src/oauth2client/models.ts +28 -0
- package/src/oauth2client/oauth2client.ts +254 -34
- package/src/utils/base64.ts +12 -0
|
@@ -28,6 +28,9 @@ export interface AuthOptions {
|
|
|
28
28
|
};
|
|
29
29
|
i18n?: ICloudbaseConfig['i18n'];
|
|
30
30
|
useWxCloud?: boolean;
|
|
31
|
+
eventBus?: any;
|
|
32
|
+
detectSessionInUrl?: boolean;
|
|
33
|
+
debug?: boolean;
|
|
31
34
|
}
|
|
32
35
|
export declare class Auth {
|
|
33
36
|
private static parseParamsToSearch;
|
|
@@ -54,15 +57,29 @@ export declare class Auth {
|
|
|
54
57
|
grantProviderToken(params: GrantProviderTokenRequest, useWxCloud?: boolean): Promise<GrantProviderTokenResponse>;
|
|
55
58
|
patchProviderToken(params: PatchProviderTokenRequest): Promise<PatchProviderTokenResponse>;
|
|
56
59
|
signInWithProvider(params: SignInWithProviderRequest, useWxCloud?: boolean): Promise<Credentials>;
|
|
60
|
+
toBindIdentity(params: {
|
|
61
|
+
provider_token: string;
|
|
62
|
+
provider: string;
|
|
63
|
+
credentials?: Credentials;
|
|
64
|
+
fireEvent?: boolean;
|
|
65
|
+
}): Promise<any>;
|
|
66
|
+
getInitialSession(): Promise<{
|
|
67
|
+
data: {
|
|
68
|
+
session: Credentials;
|
|
69
|
+
user?: any;
|
|
70
|
+
} | null;
|
|
71
|
+
error: Error | null;
|
|
72
|
+
}>;
|
|
57
73
|
signInCustom(params: SignInCustomRequest): Promise<Credentials>;
|
|
58
74
|
signInWithWechat(params?: any): Promise<Credentials>;
|
|
59
|
-
bindWithProvider(params: BindWithProviderRequest): Promise<void>;
|
|
75
|
+
bindWithProvider(params: BindWithProviderRequest, credentials?: Credentials): Promise<void>;
|
|
60
76
|
getUserProfile(params: {
|
|
61
77
|
version?: string;
|
|
62
78
|
}): Promise<UserProfile>;
|
|
63
79
|
getUserInfo(params?: {
|
|
64
80
|
version?: string;
|
|
65
81
|
query?: string;
|
|
82
|
+
credentials?: Credentials;
|
|
66
83
|
}): Promise<UserInfo>;
|
|
67
84
|
getWedaUserInfo(): Promise<any>;
|
|
68
85
|
deleteMe(params: WithSudoRequest): Promise<UserProfile>;
|
|
@@ -120,4 +137,5 @@ export declare class Auth {
|
|
|
120
137
|
getUserBehaviorLog(params: GetUserBehaviorLog): Promise<GetUserBehaviorLogRes>;
|
|
121
138
|
modifyPassword(params: ModifyUserBasicInfoRequest): Promise<void>;
|
|
122
139
|
modifyPasswordWithoutLogin(params: ModifyPasswordWithoutLoginRequest): Promise<void>;
|
|
140
|
+
private restoreUrlState;
|
|
123
141
|
}
|
|
@@ -108,3 +108,25 @@ export declare enum ErrorType {
|
|
|
108
108
|
CAPTCHA_REQUIRED = "captcha_required",
|
|
109
109
|
CAPTCHA_INVALID = "captcha_invalid"
|
|
110
110
|
}
|
|
111
|
+
export declare const LOGIN_STATE_CHANGED_TYPE: {
|
|
112
|
+
SIGN_OUT: string;
|
|
113
|
+
SIGN_IN: string;
|
|
114
|
+
CREDENTIALS_ERROR: string;
|
|
115
|
+
};
|
|
116
|
+
export declare const AUTH_STATE_CHANGED_TYPE: {
|
|
117
|
+
SIGNED_OUT: string;
|
|
118
|
+
SIGNED_IN: string;
|
|
119
|
+
INITIAL_SESSION: string;
|
|
120
|
+
PASSWORD_RECOVERY: string;
|
|
121
|
+
TOKEN_REFRESHED: string;
|
|
122
|
+
USER_UPDATED: string;
|
|
123
|
+
BIND_IDENTITY: string;
|
|
124
|
+
};
|
|
125
|
+
export declare const EVENTS: {
|
|
126
|
+
LOGIN_STATE_CHANGED: string;
|
|
127
|
+
AUTH_STATE_CHANGED: string;
|
|
128
|
+
};
|
|
129
|
+
export declare const OAUTH_TYPE: {
|
|
130
|
+
SIGN_IN: string;
|
|
131
|
+
BIND_IDENTITY: string;
|
|
132
|
+
};
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { SimpleStorage, RequestFunction } from '../oauth2client/interface';
|
|
2
2
|
import { AuthClientRequestOptions } from '../oauth2client/models';
|
|
3
3
|
import { SDKAdapterInterface } from '@cloudbase/adapter-interface';
|
|
4
|
+
import { Auth } from '../auth/apis';
|
|
4
5
|
export interface CaptchaOptions {
|
|
6
|
+
env: string;
|
|
5
7
|
clientId: string;
|
|
6
8
|
request: RequestFunction;
|
|
7
9
|
storage: SimpleStorage;
|
|
@@ -9,6 +11,7 @@ export interface CaptchaOptions {
|
|
|
9
11
|
adapter?: SDKAdapterInterface & {
|
|
10
12
|
isMatch?: () => boolean;
|
|
11
13
|
};
|
|
14
|
+
oauthInstance?: Auth;
|
|
12
15
|
}
|
|
13
16
|
type OpenURIWithCallbackFuction = (url: string) => Promise<CaptchaToken>;
|
|
14
17
|
export interface CaptchaToken {
|
|
@@ -31,7 +34,6 @@ export declare class Captcha {
|
|
|
31
34
|
isMatch(): boolean;
|
|
32
35
|
request<T>(url: string, options?: CaptchaRequestOptions): Promise<T>;
|
|
33
36
|
private getDefaultOpenURIWithCallback;
|
|
34
|
-
private defaultOpenURIWithCallback;
|
|
35
37
|
private getCaptchaToken;
|
|
36
38
|
private appendCaptchaTokenToURL;
|
|
37
39
|
private saveCaptchaToken;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,13 +1,22 @@
|
|
|
1
1
|
import { OAuth2Client } from './oauth2client/oauth2client';
|
|
2
2
|
import { AuthOptions, Auth } from './auth/apis';
|
|
3
|
+
import { Credentials } from './oauth2client/models';
|
|
3
4
|
export { Auth } from './auth/apis';
|
|
4
|
-
export { AUTH_API_PREFIX } from './auth/consts';
|
|
5
|
+
export { AUTH_API_PREFIX, OAUTH_TYPE } from './auth/consts';
|
|
6
|
+
export { AuthError } from './auth/auth-error';
|
|
5
7
|
export * as authModels from './auth/models';
|
|
6
|
-
export type { ProviderProfile } from './auth/models';
|
|
8
|
+
export type { ProviderProfile, UserInfo, ModifyUserBasicInfoRequest } from './auth/models';
|
|
7
9
|
export type { Credentials, OAuth2ClientOptions, ResponseError, AuthClientRequestOptions } from './oauth2client/models';
|
|
8
10
|
export type { AuthOptions } from './auth/apis';
|
|
11
|
+
export { weappJwtDecodeAll } from './utils/base64';
|
|
12
|
+
export { LOGIN_STATE_CHANGED_TYPE, EVENTS, AUTH_STATE_CHANGED_TYPE } from './auth/consts';
|
|
9
13
|
export declare class CloudbaseOAuth {
|
|
10
14
|
oauth2client: OAuth2Client;
|
|
11
15
|
authApi: Auth;
|
|
16
|
+
private detectSessionInUrl;
|
|
12
17
|
constructor(authOptions: AuthOptions);
|
|
18
|
+
initializeSession(onUserObtained?: (data: {
|
|
19
|
+
session: Credentials;
|
|
20
|
+
user?: any;
|
|
21
|
+
}) => void | Promise<void>): void;
|
|
13
22
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Credentials, AuthClientRequestOptions } from './models';
|
|
2
2
|
export declare abstract class AuthClient {
|
|
3
3
|
abstract request: RequestFunction;
|
|
4
|
-
abstract setCredentials(credentials?: Credentials): void
|
|
4
|
+
abstract setCredentials(credentials?: Credentials): Promise<void>;
|
|
5
5
|
abstract getAccessToken(): Promise<string>;
|
|
6
6
|
}
|
|
7
7
|
export type RequestFunction = <T>(url: string, options?: AuthClientRequestOptions) => Promise<T>;
|
|
@@ -35,6 +35,7 @@ export interface AuthClientRequestOptions extends RequestOptions {
|
|
|
35
35
|
withBasicAuth?: boolean;
|
|
36
36
|
retry?: number;
|
|
37
37
|
useWxCloud?: boolean;
|
|
38
|
+
getCredentials?: () => Credentials | Promise<Credentials | null> | null;
|
|
38
39
|
[key: string]: any;
|
|
39
40
|
}
|
|
40
41
|
export interface OAuth2ClientOptions {
|
|
@@ -57,4 +58,17 @@ export interface OAuth2ClientOptions {
|
|
|
57
58
|
onCredentialsError?: AuthOptions['onCredentialsError'];
|
|
58
59
|
i18n?: ICloudbaseConfig['i18n'];
|
|
59
60
|
useWxCloud?: boolean;
|
|
61
|
+
eventBus?: any;
|
|
62
|
+
debug?: boolean;
|
|
63
|
+
getInitialSession?: () => Promise<{
|
|
64
|
+
data: {
|
|
65
|
+
session: Credentials;
|
|
66
|
+
user?: any;
|
|
67
|
+
} | null;
|
|
68
|
+
error: Error | null;
|
|
69
|
+
}>;
|
|
70
|
+
onInitialSessionObtained?: (data: {
|
|
71
|
+
session: Credentials;
|
|
72
|
+
user?: any;
|
|
73
|
+
}) => void | Promise<void>;
|
|
60
74
|
}
|
|
@@ -23,11 +23,45 @@ declare class DefaultStorage implements SimpleStorage {
|
|
|
23
23
|
setItemSync(key: string, value: string): void;
|
|
24
24
|
}
|
|
25
25
|
export declare const defaultStorage: DefaultStorage;
|
|
26
|
+
interface LocalCredentialsOptions {
|
|
27
|
+
tokenSectionName: string;
|
|
28
|
+
storage: SimpleStorage;
|
|
29
|
+
clientId: string;
|
|
30
|
+
credentials?: Credentials;
|
|
31
|
+
}
|
|
32
|
+
declare class LocalCredentials {
|
|
33
|
+
private tokenSectionName;
|
|
34
|
+
private storage;
|
|
35
|
+
private clientId;
|
|
36
|
+
private credentials;
|
|
37
|
+
private accessKeyCredentials;
|
|
38
|
+
private singlePromise;
|
|
39
|
+
constructor(options: LocalCredentialsOptions);
|
|
40
|
+
getStorageCredentialsSync(): Credentials | null;
|
|
41
|
+
setCredentials(credentials?: Credentials): Promise<void>;
|
|
42
|
+
setAccessKeyCredentials(credentials?: Credentials): void;
|
|
43
|
+
getCredentials(): Promise<Credentials | null>;
|
|
44
|
+
private getStorageCredentials;
|
|
45
|
+
}
|
|
26
46
|
export declare class OAuth2Client implements AuthClient {
|
|
27
47
|
private static defaultRetry;
|
|
28
48
|
private static minRetry;
|
|
29
49
|
private static maxRetry;
|
|
30
50
|
private static retryInterval;
|
|
51
|
+
localCredentials: LocalCredentials;
|
|
52
|
+
initializePromise: Promise<{
|
|
53
|
+
error: Error | null;
|
|
54
|
+
}> | null;
|
|
55
|
+
protected lockAcquired: boolean;
|
|
56
|
+
protected pendingInLock: Promise<any>[];
|
|
57
|
+
protected logDebugMessages: boolean;
|
|
58
|
+
protected getInitialSession?: () => Promise<{
|
|
59
|
+
data: {
|
|
60
|
+
session: Credentials;
|
|
61
|
+
user?: any;
|
|
62
|
+
} | null;
|
|
63
|
+
error: Error | null;
|
|
64
|
+
}>;
|
|
31
65
|
private apiOrigin;
|
|
32
66
|
private apiPath;
|
|
33
67
|
private clientId;
|
|
@@ -35,7 +69,6 @@ export declare class OAuth2Client implements AuthClient {
|
|
|
35
69
|
private retry;
|
|
36
70
|
private clientSecret?;
|
|
37
71
|
private baseRequest;
|
|
38
|
-
private localCredentials;
|
|
39
72
|
private storage;
|
|
40
73
|
private deviceID?;
|
|
41
74
|
private tokenInURL?;
|
|
@@ -45,9 +78,25 @@ export declare class OAuth2Client implements AuthClient {
|
|
|
45
78
|
private anonymousSignInFunc;
|
|
46
79
|
private wxCloud;
|
|
47
80
|
private useWxCloud;
|
|
81
|
+
private eventBus;
|
|
48
82
|
private basicAuth;
|
|
49
83
|
private onCredentialsError;
|
|
84
|
+
private onInitialSessionObtained?;
|
|
50
85
|
constructor(options: OAuth2ClientOptions);
|
|
86
|
+
setGetInitialSession(callback: () => Promise<{
|
|
87
|
+
data: {
|
|
88
|
+
session: Credentials;
|
|
89
|
+
user?: any;
|
|
90
|
+
} | null;
|
|
91
|
+
error: Error | null;
|
|
92
|
+
}>): void;
|
|
93
|
+
setOnInitialSessionObtained(callback: (data: {
|
|
94
|
+
session: Credentials;
|
|
95
|
+
user?: any;
|
|
96
|
+
}) => void | Promise<void>): void;
|
|
97
|
+
initialize(): Promise<{
|
|
98
|
+
error: Error | null;
|
|
99
|
+
}>;
|
|
51
100
|
setCredentials(credentials?: Credentials): Promise<void>;
|
|
52
101
|
setAccessKeyCredentials(credentials?: Credentials): void;
|
|
53
102
|
getAccessToken(): Promise<string>;
|
|
@@ -58,7 +107,10 @@ export declare class OAuth2Client implements AuthClient {
|
|
|
58
107
|
getCredentialsAsync(): Promise<Credentials | null>;
|
|
59
108
|
getScope(): Promise<string>;
|
|
60
109
|
getGroups(): Promise<string[]>;
|
|
61
|
-
refreshToken(credentials: Credentials
|
|
110
|
+
refreshToken(credentials: Credentials, options?: {
|
|
111
|
+
throwError?: boolean;
|
|
112
|
+
}): Promise<Credentials>;
|
|
113
|
+
private _refreshToken;
|
|
62
114
|
private anonymousLogin;
|
|
63
115
|
private checkRetry;
|
|
64
116
|
private formatRetry;
|
|
@@ -67,5 +119,9 @@ export declare class OAuth2Client implements AuthClient {
|
|
|
67
119
|
private defaultRefreshTokenFunc;
|
|
68
120
|
private getDeviceId;
|
|
69
121
|
private unAuthenticatedError;
|
|
122
|
+
private _debug;
|
|
123
|
+
private _initialize;
|
|
124
|
+
private _acquireLock;
|
|
125
|
+
private _getCredentials;
|
|
70
126
|
}
|
|
71
127
|
export {};
|
|
@@ -2,3 +2,8 @@ export declare function weBtoa(string: string): string;
|
|
|
2
2
|
export declare const weAtob: (string: string) => string;
|
|
3
3
|
export declare function base64_url_decode(str: string): string;
|
|
4
4
|
export declare function weappJwtDecode(token: string, options?: any): any;
|
|
5
|
+
export declare function weappJwtDecodeAll(token: string): {
|
|
6
|
+
claims: any;
|
|
7
|
+
header: any;
|
|
8
|
+
signature: any;
|
|
9
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cloudbase/oauth",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.24.0",
|
|
4
4
|
"description": "cloudbase javascript sdk auth componets",
|
|
5
5
|
"main": "dist/cjs/index.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -19,16 +19,16 @@
|
|
|
19
19
|
"precommit": "npm run lint"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@cloudbase/utilities": "2.
|
|
22
|
+
"@cloudbase/utilities": "2.24.0"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@babel/preset-env": "^7.25.3",
|
|
26
|
-
"@cloudbase/types": "2.
|
|
26
|
+
"@cloudbase/types": "2.24.0",
|
|
27
27
|
"@types/node": "^22.5.4",
|
|
28
28
|
"terser-webpack-plugin": "^3.0.2",
|
|
29
29
|
"ts-loader": "^9.5.1",
|
|
30
30
|
"webpack-bundle-analyzer": "^4.9.1"
|
|
31
31
|
},
|
|
32
32
|
"license": "Apache-2.0",
|
|
33
|
-
"gitHead": "
|
|
33
|
+
"gitHead": "7dac230344ecae3eec15358b2f85d782fde51839"
|
|
34
34
|
}
|
package/src/auth/apis.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
import { ApiUrls, ApiUrlsV2, ErrorType } from './consts'
|
|
3
|
+
import { ApiUrls, ApiUrlsV2, AUTH_STATE_CHANGED_TYPE, ErrorType, EVENTS, OAUTH_TYPE } from './consts'
|
|
4
4
|
import {
|
|
5
5
|
GetVerificationRequest,
|
|
6
6
|
GetVerificationResponse,
|
|
@@ -69,6 +69,7 @@ import { deepClone } from '../utils'
|
|
|
69
69
|
import MyURLSearchParams from '../utils/urlSearchParams'
|
|
70
70
|
import { SDKAdapterInterface } from '@cloudbase/adapter-interface'
|
|
71
71
|
import { ICloudbaseConfig } from '@cloudbase/types'
|
|
72
|
+
import { AuthError } from '..'
|
|
72
73
|
|
|
73
74
|
function getEncryptUtils(isEncrypt, adapter: SDKAdapterInterface) {
|
|
74
75
|
const getUtils = () => {
|
|
@@ -119,6 +120,16 @@ export interface AuthOptions {
|
|
|
119
120
|
headers?: { [key: string]: string }
|
|
120
121
|
i18n?: ICloudbaseConfig['i18n']
|
|
121
122
|
useWxCloud?: boolean
|
|
123
|
+
eventBus?: any
|
|
124
|
+
/**
|
|
125
|
+
* Set to true if you want to automatically detect OAuth grants in the URL
|
|
126
|
+
* and exchange the code for credentials.
|
|
127
|
+
*/
|
|
128
|
+
detectSessionInUrl?: boolean
|
|
129
|
+
/**
|
|
130
|
+
* Enable debug logging
|
|
131
|
+
*/
|
|
132
|
+
debug?: boolean
|
|
122
133
|
}
|
|
123
134
|
|
|
124
135
|
/**
|
|
@@ -158,16 +169,19 @@ export class Auth {
|
|
|
158
169
|
onCredentialsError: opts.onCredentialsError,
|
|
159
170
|
headers: opts.headers || {},
|
|
160
171
|
i18n: opts.i18n,
|
|
172
|
+
debug: opts.debug,
|
|
161
173
|
}
|
|
162
174
|
oAuth2Client = new OAuth2Client(initOptions)
|
|
163
175
|
}
|
|
164
176
|
if (!request) {
|
|
165
177
|
const baseRequest = oAuth2Client.request.bind(oAuth2Client)
|
|
166
178
|
const captcha = new Captcha({
|
|
179
|
+
env: opts.env,
|
|
167
180
|
clientId: opts.clientId,
|
|
168
181
|
request: baseRequest,
|
|
169
182
|
storage: opts.storage,
|
|
170
183
|
adapter: opts.adapter,
|
|
184
|
+
oauthInstance: this,
|
|
171
185
|
...opts.captchaOptions,
|
|
172
186
|
})
|
|
173
187
|
request = captcha.request.bind(captcha)
|
|
@@ -443,6 +457,154 @@ export class Auth {
|
|
|
443
457
|
return Promise.resolve(credentials)
|
|
444
458
|
}
|
|
445
459
|
|
|
460
|
+
public async toBindIdentity(params: {
|
|
461
|
+
provider_token: string
|
|
462
|
+
provider: string
|
|
463
|
+
credentials?: Credentials
|
|
464
|
+
fireEvent?: boolean
|
|
465
|
+
}) {
|
|
466
|
+
const credentials = params.credentials || (await this.config.credentialsClient.localCredentials.getCredentials())
|
|
467
|
+
let res: any
|
|
468
|
+
try {
|
|
469
|
+
await this.bindWithProvider(
|
|
470
|
+
{
|
|
471
|
+
provider_token: params.provider_token,
|
|
472
|
+
},
|
|
473
|
+
credentials,
|
|
474
|
+
)
|
|
475
|
+
res = { data: { type: OAUTH_TYPE.BIND_IDENTITY, provider: params.provider }, error: null }
|
|
476
|
+
} catch (error) {
|
|
477
|
+
res = { data: { type: OAUTH_TYPE.BIND_IDENTITY }, error: new AuthError(error) }
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
if (params.fireEvent) {
|
|
481
|
+
this.config.eventBus?.fire?.(EVENTS.AUTH_STATE_CHANGED, {
|
|
482
|
+
event: AUTH_STATE_CHANGED_TYPE.BIND_IDENTITY,
|
|
483
|
+
info: res,
|
|
484
|
+
})
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
return res
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
/**
|
|
491
|
+
* 获取初始 session(如从 URL 中的 OAuth 回调)。
|
|
492
|
+
* 用于 OAuth2Client.initialize() 回调。
|
|
493
|
+
* 内部处理 URL 检测、OAuth 验证,返回 credentials 和 user。
|
|
494
|
+
* 不调用 setCredentials,由 OAuth2Client 负责保存。
|
|
495
|
+
*
|
|
496
|
+
* @returns { data: { session: Credentials; user?: any } | null, error: Error | null }
|
|
497
|
+
*/
|
|
498
|
+
public async getInitialSession(): Promise<{
|
|
499
|
+
data: { session: Credentials; user?: any } | null
|
|
500
|
+
error: Error | null
|
|
501
|
+
}> {
|
|
502
|
+
let data: any = {}
|
|
503
|
+
try {
|
|
504
|
+
// Check if running in browser
|
|
505
|
+
if (typeof window === 'undefined' || typeof document === 'undefined') {
|
|
506
|
+
return { data: null, error: null }
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
// Parse URL parameters
|
|
510
|
+
const localSearch = new URLSearchParams(location?.search)
|
|
511
|
+
const code = localSearch.get('code')
|
|
512
|
+
const state = localSearch.get('state')
|
|
513
|
+
|
|
514
|
+
// No OAuth callback detected
|
|
515
|
+
if (!code || !state) {
|
|
516
|
+
return { data: null, error: null }
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
// Get provider from sessionStorage (saved during signInWithOAuth)
|
|
520
|
+
let cacheData: {
|
|
521
|
+
provider?: string
|
|
522
|
+
search?: string
|
|
523
|
+
hash?: string
|
|
524
|
+
type?: (typeof OAUTH_TYPE)[keyof typeof OAUTH_TYPE]
|
|
525
|
+
} | null = null
|
|
526
|
+
try {
|
|
527
|
+
cacheData = JSON.parse(sessionStorage.getItem(state) || 'null')
|
|
528
|
+
} catch {
|
|
529
|
+
// ignore
|
|
530
|
+
}
|
|
531
|
+
data = { type: cacheData?.type }
|
|
532
|
+
// Check for error in URL
|
|
533
|
+
const errorParam = localSearch.get('error')
|
|
534
|
+
const errorDescription = localSearch.get('error_description')
|
|
535
|
+
if (errorParam || errorDescription) {
|
|
536
|
+
return {
|
|
537
|
+
data,
|
|
538
|
+
error: new AuthError({ message: errorDescription || errorParam || 'Unknown error from OAuth provider' }),
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
const provider = cacheData?.provider || localSearch.get('provider')
|
|
543
|
+
|
|
544
|
+
if (!provider) {
|
|
545
|
+
return { data, error: new AuthError({ message: 'Provider is required for OAuth verification' }) }
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
// 获取当前页面的 redirect_uri
|
|
549
|
+
const redirectUri = location.origin + location.pathname
|
|
550
|
+
|
|
551
|
+
// Step 1: 获取 provider token
|
|
552
|
+
const { provider_token: providerToken } = await this.grantProviderToken({
|
|
553
|
+
provider_id: provider,
|
|
554
|
+
provider_redirect_uri: redirectUri,
|
|
555
|
+
provider_code: code,
|
|
556
|
+
})
|
|
557
|
+
|
|
558
|
+
let credentials: Credentials
|
|
559
|
+
let user: any = null
|
|
560
|
+
let res: any
|
|
561
|
+
|
|
562
|
+
if (cacheData.type === OAUTH_TYPE.BIND_IDENTITY) {
|
|
563
|
+
credentials = await this.config.credentialsClient.localCredentials.getCredentials()
|
|
564
|
+
res = await this.toBindIdentity({ provider, provider_token: providerToken, credentials })
|
|
565
|
+
} else if (cacheData.type === OAUTH_TYPE.SIGN_IN) {
|
|
566
|
+
res = this.getParamsByVersion({ provider }, 'AUTH_SIGN_IN_WITH_PROVIDER_URL')
|
|
567
|
+
|
|
568
|
+
// Step 2: 用 provider token 换取 credentials(直接调用 API,不触发 setCredentials)
|
|
569
|
+
credentials = await this.config.request<Credentials>(res.url, {
|
|
570
|
+
method: 'POST',
|
|
571
|
+
body: { provider_token: providerToken },
|
|
572
|
+
})
|
|
573
|
+
|
|
574
|
+
// Step 3: 获取 user info,传入 getCredentials 函数避免死锁
|
|
575
|
+
// 不调用 setCredentials,由 OAuth2Client._initialize 负责保存
|
|
576
|
+
try {
|
|
577
|
+
user = await this.getUserInfo({ credentials })
|
|
578
|
+
} catch (e) {
|
|
579
|
+
console.error('get user info error', e)
|
|
580
|
+
// 获取 user 失败不影响登录流程
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
res = { data: { ...data, session: credentials, user }, error: null }
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
// Clean up URL parameters and restore original URL state
|
|
587
|
+
localSearch.delete('code')
|
|
588
|
+
localSearch.delete('state')
|
|
589
|
+
localSearch.delete('provider')
|
|
590
|
+
this.restoreUrlState(
|
|
591
|
+
cacheData?.search === undefined ? `?${localSearch.toString()}` : cacheData.search,
|
|
592
|
+
cacheData?.hash || location.hash,
|
|
593
|
+
)
|
|
594
|
+
|
|
595
|
+
// Remove session storage
|
|
596
|
+
try {
|
|
597
|
+
sessionStorage.removeItem(state)
|
|
598
|
+
} catch {
|
|
599
|
+
// ignore
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
return res
|
|
603
|
+
} catch (error) {
|
|
604
|
+
return { data, error: new AuthError(error) }
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
|
|
446
608
|
/**
|
|
447
609
|
* Signin with custom.
|
|
448
610
|
* @param {SignInCustomRequest} params A SignInCustomRequest object.
|
|
@@ -476,11 +638,12 @@ export class Auth {
|
|
|
476
638
|
* @param {BindWithProviderRequest} params A BindWithProviderRequest object.
|
|
477
639
|
* @return {Promise<void>} A Promise<any> object.
|
|
478
640
|
*/
|
|
479
|
-
public async bindWithProvider(params: BindWithProviderRequest): Promise<void> {
|
|
641
|
+
public async bindWithProvider(params: BindWithProviderRequest, credentials?: Credentials): Promise<void> {
|
|
480
642
|
return this.config.request<any>(ApiUrls.PROVIDER_BIND_URL, {
|
|
481
643
|
method: 'POST',
|
|
482
644
|
body: params,
|
|
483
645
|
withCredentials: true,
|
|
646
|
+
getCredentials: credentials ? () => credentials : undefined,
|
|
484
647
|
})
|
|
485
648
|
}
|
|
486
649
|
|
|
@@ -494,9 +657,14 @@ export class Auth {
|
|
|
494
657
|
|
|
495
658
|
/**
|
|
496
659
|
* Get the user info.
|
|
660
|
+
* @param params.getCredentials Optional custom getCredentials function to bypass default getCredentials() and avoid deadlock
|
|
497
661
|
* @return {Promise<UserInfo>} A Promise<UserProfile> object.
|
|
498
662
|
*/
|
|
499
|
-
public async getUserInfo(params: {
|
|
663
|
+
public async getUserInfo(params: {
|
|
664
|
+
version?: string
|
|
665
|
+
query?: string
|
|
666
|
+
credentials?: Credentials
|
|
667
|
+
} = {},): Promise<UserInfo> {
|
|
500
668
|
const res = this.getParamsByVersion(params, 'USER_ME_URL')
|
|
501
669
|
|
|
502
670
|
if (res.params?.query) {
|
|
@@ -507,6 +675,7 @@ export class Auth {
|
|
|
507
675
|
const userInfo = await this.config.request<UserInfo>(res.url, {
|
|
508
676
|
method: 'GET',
|
|
509
677
|
withCredentials: true,
|
|
678
|
+
getCredentials: params.credentials ? () => params.credentials : undefined,
|
|
510
679
|
})
|
|
511
680
|
|
|
512
681
|
if (userInfo.sub) {
|
|
@@ -708,7 +877,8 @@ export class Auth {
|
|
|
708
877
|
}
|
|
709
878
|
|
|
710
879
|
/**
|
|
711
|
-
* Patch the user profile.
|
|
880
|
+
* Patch the user profile. 没有和数据源同步
|
|
881
|
+
* @deprecated use updateUserBasicInfo
|
|
712
882
|
* @param {UserProfile} params A UserProfile Object.
|
|
713
883
|
* @return {Promise<UserProfile>} A Promise<UserProfile> object.
|
|
714
884
|
*/
|
|
@@ -1102,4 +1272,19 @@ export class Auth {
|
|
|
1102
1272
|
},
|
|
1103
1273
|
})
|
|
1104
1274
|
}
|
|
1275
|
+
|
|
1276
|
+
/**
|
|
1277
|
+
* Restore URL state after OAuth callback
|
|
1278
|
+
*/
|
|
1279
|
+
private restoreUrlState(search?: string, hash?: string): void {
|
|
1280
|
+
if (search === undefined) return
|
|
1281
|
+
try {
|
|
1282
|
+
const url = new URL(window.location.href)
|
|
1283
|
+
url.search = search
|
|
1284
|
+
url.hash = hash || ''
|
|
1285
|
+
window.history.replaceState(null, '', url.toString())
|
|
1286
|
+
} catch {
|
|
1287
|
+
// ignore
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1105
1290
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export class AuthError extends Error {
|
|
2
|
+
/**
|
|
3
|
+
* Error code associated with the error. Most errors coming from
|
|
4
|
+
* HTTP responses will have a code, though some errors that occur
|
|
5
|
+
* before a response is received will not have one present. In that
|
|
6
|
+
* case {@link #status} will also be undefined.
|
|
7
|
+
*/
|
|
8
|
+
code: (string & {}) | undefined
|
|
9
|
+
|
|
10
|
+
/** HTTP status code that caused the error. */
|
|
11
|
+
status: number | undefined
|
|
12
|
+
|
|
13
|
+
protected __isAuthError = true
|
|
14
|
+
|
|
15
|
+
constructor(error) {
|
|
16
|
+
super(error.error_description || error.message)
|
|
17
|
+
this.name = 'AuthError'
|
|
18
|
+
this.status = error.error
|
|
19
|
+
this.code = error.error_code
|
|
20
|
+
}
|
|
21
|
+
}
|
package/src/auth/consts.ts
CHANGED
|
@@ -119,3 +119,31 @@ export enum ErrorType {
|
|
|
119
119
|
CAPTCHA_REQUIRED = 'captcha_required',
|
|
120
120
|
CAPTCHA_INVALID = 'captcha_invalid',
|
|
121
121
|
}
|
|
122
|
+
|
|
123
|
+
export const LOGIN_STATE_CHANGED_TYPE = {
|
|
124
|
+
SIGN_OUT: 'sign_out',
|
|
125
|
+
SIGN_IN: 'sign_in',
|
|
126
|
+
CREDENTIALS_ERROR: 'credentials_error',
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export const AUTH_STATE_CHANGED_TYPE = {
|
|
130
|
+
SIGNED_OUT: 'SIGNED_OUT',
|
|
131
|
+
SIGNED_IN: 'SIGNED_IN',
|
|
132
|
+
INITIAL_SESSION: 'INITIAL_SESSION',
|
|
133
|
+
PASSWORD_RECOVERY: 'PASSWORD_RECOVERY',
|
|
134
|
+
TOKEN_REFRESHED: 'TOKEN_REFRESHED',
|
|
135
|
+
USER_UPDATED: 'USER_UPDATED',
|
|
136
|
+
BIND_IDENTITY: 'BIND_IDENTITY',
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export const EVENTS = {
|
|
140
|
+
// 登录态改变后触发
|
|
141
|
+
LOGIN_STATE_CHANGED: 'loginStateChanged',
|
|
142
|
+
// 授权态改变后触发
|
|
143
|
+
AUTH_STATE_CHANGED: 'authStateChanged',
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export const OAUTH_TYPE = {
|
|
147
|
+
SIGN_IN: 'sign_in',
|
|
148
|
+
BIND_IDENTITY: 'bind_identity',
|
|
149
|
+
}
|
package/src/auth/models.ts
CHANGED