@cloudbase/auth 2.26.1 → 2.26.3
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/adapter.js +2 -1
- package/dist/cjs/index.d.ts +74 -72
- package/dist/cjs/index.js +1772 -1672
- package/dist/cjs/type.d.ts +10 -0
- package/dist/cjs/type.js +1 -1
- package/dist/cjs/utils.d.ts +1 -1
- package/dist/cjs/utils.js +2 -1
- package/dist/cjs/v1-compat.d.ts +77 -0
- package/dist/cjs/v1-compat.js +423 -0
- package/dist/esm/adapter.js +2 -1
- package/dist/esm/index.d.ts +74 -72
- package/dist/esm/index.js +1770 -1673
- package/dist/esm/type.d.ts +10 -0
- package/dist/esm/type.js +1 -1
- package/dist/esm/utils.d.ts +1 -1
- package/dist/esm/utils.js +2 -1
- package/dist/esm/v1-compat.d.ts +77 -0
- package/dist/esm/v1-compat.js +419 -0
- package/dist/miniprogram/index.js +1 -1
- package/package.json +5 -5
- package/src/adapter.ts +1 -0
- package/src/index.ts +1740 -1666
- package/src/type.ts +11 -0
- package/src/utils.ts +3 -1
- package/src/v1-compat.ts +499 -0
package/src/index.ts
CHANGED
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
weAppJwtDecodeAll,
|
|
15
15
|
AuthError,
|
|
16
16
|
authModels,
|
|
17
|
+
DEFAULT_NODE_ACCESS_SCOPE,
|
|
17
18
|
} from '@cloudbase/oauth'
|
|
18
19
|
import { useAuthAdapter } from './adapter'
|
|
19
20
|
import {
|
|
@@ -28,6 +29,13 @@ import {
|
|
|
28
29
|
useDefaultAdapter,
|
|
29
30
|
} from './utilities'
|
|
30
31
|
import { saveToBrowserSession, getBrowserSession, removeBrowserSession, addUrlSearch } from './utils'
|
|
32
|
+
import {
|
|
33
|
+
AuthV1Compat,
|
|
34
|
+
WeixinAuthProvider,
|
|
35
|
+
CustomAuthProvider,
|
|
36
|
+
AnonymousAuthProvider,
|
|
37
|
+
applyUserV1Compat,
|
|
38
|
+
} from './v1-compat'
|
|
31
39
|
import { utils } from '@cloudbase/utilities'
|
|
32
40
|
import {
|
|
33
41
|
CommonRes,
|
|
@@ -58,6 +66,7 @@ import {
|
|
|
58
66
|
UpdateUserReq,
|
|
59
67
|
UpdateUserWithVerificationRes,
|
|
60
68
|
VerifyOAuthReq,
|
|
69
|
+
VerifyOAuthRes,
|
|
61
70
|
VerifyOtpReq,
|
|
62
71
|
} from './type'
|
|
63
72
|
|
|
@@ -327,6 +336,10 @@ export class User implements IUser {
|
|
|
327
336
|
})
|
|
328
337
|
}
|
|
329
338
|
}
|
|
339
|
+
|
|
340
|
+
// 应用 v1 兼容方法到 User 类
|
|
341
|
+
applyUserV1Compat(User)
|
|
342
|
+
|
|
330
343
|
interface ILoginStateOptions extends IUserOptions {
|
|
331
344
|
envId: string
|
|
332
345
|
}
|
|
@@ -362,18 +375,21 @@ export class LoginState implements ILoginState {
|
|
|
362
375
|
}
|
|
363
376
|
}
|
|
364
377
|
|
|
365
|
-
|
|
366
|
-
|
|
378
|
+
interface IAuthConfig extends ICloudbaseAuthConfig {
|
|
379
|
+
cache: ICloudbaseCache
|
|
380
|
+
request?: ICloudbaseRequest
|
|
381
|
+
runtime?: string
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
class Auth extends AuthV1Compat {
|
|
385
|
+
readonly config: IAuthConfig
|
|
367
386
|
oauthInstance: CloudbaseOAuth
|
|
368
387
|
readonly cache: ICloudbaseCache
|
|
369
388
|
private listeners: Map<string, Set<OnAuthStateChangeCallback>> = new Map()
|
|
370
389
|
private hasListenerSetUp = false
|
|
371
390
|
|
|
372
|
-
constructor(config:
|
|
373
|
-
|
|
374
|
-
request?: ICloudbaseRequest
|
|
375
|
-
runtime?: string
|
|
376
|
-
},) {
|
|
391
|
+
constructor(config: IAuthConfig) {
|
|
392
|
+
super()
|
|
377
393
|
this.config = config
|
|
378
394
|
this.oauthInstance = config.oauthInstance
|
|
379
395
|
this.cache = config.cache
|
|
@@ -381,1060 +397,827 @@ class Auth {
|
|
|
381
397
|
this.setAccessKey()
|
|
382
398
|
}
|
|
383
399
|
|
|
384
|
-
|
|
385
|
-
* 绑定手机号
|
|
386
|
-
* @param phoneNumber
|
|
387
|
-
* @param phoneCode
|
|
388
|
-
*/
|
|
389
|
-
@catchErrorsDecorator({
|
|
390
|
-
title: '绑定手机号失败',
|
|
391
|
-
messages: [
|
|
392
|
-
'请确认以下各项:',
|
|
393
|
-
' 1 - 调用 auth().bindPhoneNumber() 的语法或参数是否正确',
|
|
394
|
-
' 2 - 当前环境是否开通了短信验证码登录',
|
|
395
|
-
`如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
|
|
396
|
-
],
|
|
397
|
-
})
|
|
398
|
-
public async bindPhoneNumber(params: authModels.BindPhoneRequest) {
|
|
399
|
-
return this.oauthInstance.authApi.editContact(params)
|
|
400
|
-
}
|
|
400
|
+
// ========== new auth api methods merged below ==========
|
|
401
401
|
|
|
402
402
|
/**
|
|
403
|
-
*
|
|
404
|
-
*
|
|
403
|
+
* https://supabase.com/docs/reference/javascript/auth-signinanonymously
|
|
404
|
+
* Sign in a user anonymously.
|
|
405
|
+
* const { data, error } = await auth.signInAnonymously();
|
|
406
|
+
* @param params
|
|
407
|
+
* @returns Promise<SignInRes>
|
|
405
408
|
*/
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
' 1 - 调用 auth().unbindProvider() 的语法或参数是否正确',
|
|
411
|
-
' 2 - 当前账户是否已经与此登录方式解绑',
|
|
412
|
-
`如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
|
|
413
|
-
],
|
|
414
|
-
})
|
|
415
|
-
public async unbindProvider(params: authModels.UnbindProviderRequest): Promise<void> {
|
|
416
|
-
return this.oauthInstance.authApi.unbindProvider(params)
|
|
417
|
-
}
|
|
409
|
+
async signInAnonymously(params: SignInAnonymouslyReq): Promise<SignInRes> {
|
|
410
|
+
try {
|
|
411
|
+
await this.oauthInstance.authApi.signInAnonymously(params)
|
|
412
|
+
const loginState = await this.createLoginState()
|
|
418
413
|
|
|
419
|
-
|
|
420
|
-
* 更新邮箱地址
|
|
421
|
-
* @param email
|
|
422
|
-
* @param sudo_token
|
|
423
|
-
* @param verification_token
|
|
424
|
-
*/
|
|
425
|
-
@catchErrorsDecorator({
|
|
426
|
-
title: '绑定邮箱地址失败',
|
|
427
|
-
messages: [
|
|
428
|
-
'请确认以下各项:',
|
|
429
|
-
' 1 - 调用 auth().bindEmail() 的语法或参数是否正确',
|
|
430
|
-
' 2 - 当前环境是否开通了邮箱密码登录',
|
|
431
|
-
`如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
|
|
432
|
-
],
|
|
433
|
-
})
|
|
434
|
-
public bindEmail(params: authModels.BindEmailRequest) {
|
|
435
|
-
return this.oauthInstance.authApi.editContact(params)
|
|
436
|
-
}
|
|
414
|
+
const { data: { session } = {} } = await this.getSession()
|
|
437
415
|
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
*/
|
|
444
|
-
@catchErrorsDecorator({
|
|
445
|
-
title: '验证码验证失败',
|
|
446
|
-
messages: [
|
|
447
|
-
'请确认以下各项:',
|
|
448
|
-
' 1 - 调用 auth().verify() 的语法或参数是否正确',
|
|
449
|
-
' 2 - 当前环境是否开通了手机验证码/邮箱登录',
|
|
450
|
-
`如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
|
|
451
|
-
],
|
|
452
|
-
})
|
|
453
|
-
public async verify(params: authModels.VerifyRequest): Promise<authModels.VerifyResponse> {
|
|
454
|
-
return this.oauthInstance.authApi.verify(params)
|
|
416
|
+
// loginState返回是为了兼容v2版本
|
|
417
|
+
return { ...(loginState as any), data: { user: session.user, session }, error: null }
|
|
418
|
+
} catch (error) {
|
|
419
|
+
return { data: {}, error: new AuthError(error) }
|
|
420
|
+
}
|
|
455
421
|
}
|
|
456
422
|
|
|
457
423
|
/**
|
|
458
|
-
*
|
|
459
|
-
*
|
|
460
|
-
* @
|
|
461
|
-
* @
|
|
424
|
+
* https://supabase.com/docs/reference/javascript/auth-signup
|
|
425
|
+
* Sign up a new user with email or phone using a one-time password (OTP). If the account not exist, a new account will be created.
|
|
426
|
+
* @param params
|
|
427
|
+
* @returns Promise<SignUpRes>
|
|
462
428
|
*/
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
messages: [
|
|
466
|
-
'请确认以下各项:',
|
|
467
|
-
' 1 - 调用 auth().getVerification() 的语法或参数是否正确',
|
|
468
|
-
' 2 - 当前环境是否开通了手机验证码/邮箱登录',
|
|
469
|
-
`如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
|
|
470
|
-
],
|
|
471
|
-
})
|
|
472
|
-
public async getVerification(
|
|
473
|
-
params: authModels.GetVerificationRequest,
|
|
474
|
-
options?: { withCaptcha: boolean },
|
|
475
|
-
): Promise<authModels.GetVerificationResponse> {
|
|
476
|
-
if (params.phone_number) {
|
|
429
|
+
async signUp(params: authModels.SignUpRequest & { phone?: string }): Promise<SignUpRes> {
|
|
430
|
+
if (params.phone_number || params.verification_code || params.verification_token || params.provider_token) {
|
|
477
431
|
params.phone_number = this.formatPhone(params.phone_number)
|
|
432
|
+
await this.oauthInstance.authApi.signUp(params)
|
|
433
|
+
return this.createLoginState() as any
|
|
478
434
|
}
|
|
479
|
-
|
|
480
|
-
|
|
435
|
+
try {
|
|
436
|
+
// 参数校验:email或phone必填其一
|
|
437
|
+
this.validateAtLeastOne(params, [['email'], ['phone']], 'You must provide either an email or phone number')
|
|
481
438
|
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
*/
|
|
485
|
-
get currentUser() {
|
|
486
|
-
if (this.cache.mode === 'async') {
|
|
487
|
-
// async storage的平台调用此API提示
|
|
488
|
-
printWarn(
|
|
489
|
-
ERRORS.INVALID_OPERATION,
|
|
490
|
-
'current platform\'s storage is asynchronous, please use getCurrentUser instead',
|
|
491
|
-
)
|
|
492
|
-
return
|
|
493
|
-
}
|
|
439
|
+
// 第一步:发送验证码并存储 verificationInfo
|
|
440
|
+
const verificationInfo = await this.getVerification(params.email ? { email: params.email } : { phone_number: this.formatPhone(params.phone) },)
|
|
494
441
|
|
|
495
|
-
|
|
442
|
+
return {
|
|
443
|
+
data: {
|
|
444
|
+
// 第二步:等待用户输入验证码(通过 Promise 包装用户输入事件)
|
|
445
|
+
verifyOtp: async ({ token, messageId = verificationInfo.verification_id }): Promise<SignInRes> => {
|
|
446
|
+
try {
|
|
447
|
+
// 第三步:待用户输入完验证码之后,验证短信验证码
|
|
448
|
+
const verificationTokenRes = await this.verify({
|
|
449
|
+
verification_id: messageId || verificationInfo.verification_id,
|
|
450
|
+
verification_code: token,
|
|
451
|
+
})
|
|
496
452
|
|
|
497
|
-
|
|
498
|
-
|
|
453
|
+
// 第四步:注册并登录或直接登录
|
|
454
|
+
// 如果用户已经存在,直接登录
|
|
455
|
+
if (verificationInfo.is_user) {
|
|
456
|
+
await this.signIn({
|
|
457
|
+
username: params.email || this.formatPhone(params.phone),
|
|
458
|
+
verification_token: verificationTokenRes.verification_token,
|
|
459
|
+
})
|
|
460
|
+
} else {
|
|
461
|
+
// 如果用户不存在,注册用户
|
|
462
|
+
const data = JSON.parse(JSON.stringify(params))
|
|
463
|
+
delete data.email
|
|
464
|
+
delete data.phone
|
|
465
|
+
|
|
466
|
+
await this.oauthInstance.authApi.signUp({
|
|
467
|
+
...data,
|
|
468
|
+
...(params.email ? { email: params.email } : { phone_number: this.formatPhone(params.phone) }),
|
|
469
|
+
verification_token: verificationTokenRes.verification_token,
|
|
470
|
+
verification_code: token,
|
|
471
|
+
})
|
|
472
|
+
await this.createLoginState()
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
const { data: { session } = {} } = await this.getSession()
|
|
476
|
+
|
|
477
|
+
return { data: { user: session.user, session }, error: null }
|
|
478
|
+
} catch (error) {
|
|
479
|
+
return { data: {}, error: new AuthError(error) }
|
|
480
|
+
}
|
|
481
|
+
},
|
|
482
|
+
},
|
|
483
|
+
error: null,
|
|
484
|
+
}
|
|
485
|
+
} catch (error) {
|
|
486
|
+
return { data: {}, error: new AuthError(error) }
|
|
499
487
|
}
|
|
500
|
-
return null
|
|
501
488
|
}
|
|
502
489
|
|
|
503
490
|
/**
|
|
504
|
-
*
|
|
491
|
+
* https://supabase.com/docs/reference/javascript/auth-signout
|
|
492
|
+
* const result = await auth.signOut();
|
|
493
|
+
*
|
|
494
|
+
* @param params
|
|
505
495
|
*/
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
496
|
+
async signOut(params?: authModels.SignoutRequest,): Promise<authModels.SignoutResponse & { data: Object; error: AuthError }> {
|
|
497
|
+
try {
|
|
498
|
+
const { userInfoKey } = this.cache.keys
|
|
499
|
+
const res = await this.oauthInstance.authApi.signOut(params)
|
|
500
|
+
await this.cache.removeStoreAsync(userInfoKey)
|
|
501
|
+
this.setAccessKey()
|
|
502
|
+
|
|
503
|
+
this.config.eventBus?.fire(EVENTS.LOGIN_STATE_CHANGED, { eventType: LOGIN_STATE_CHANGED_TYPE.SIGN_OUT })
|
|
504
|
+
|
|
505
|
+
this.config.eventBus?.fire(EVENTS.AUTH_STATE_CHANGED, { event: AUTH_STATE_CHANGED_TYPE.SIGNED_OUT })
|
|
506
|
+
|
|
507
|
+
// res返回是为了兼容v2版本
|
|
508
|
+
return { ...res, data: {}, error: null }
|
|
509
|
+
} catch (error) {
|
|
510
|
+
return { data: {}, error: new AuthError(error) }
|
|
520
511
|
}
|
|
521
|
-
return null
|
|
522
512
|
}
|
|
523
513
|
|
|
524
|
-
// /**
|
|
525
|
-
// * 匿名登录
|
|
526
|
-
// * @returns {Promise<LoginState>}
|
|
527
|
-
// * @memberof Auth
|
|
528
|
-
// */
|
|
529
|
-
// @catchErrorsDecorator({
|
|
530
|
-
// title: '匿名登录失败',
|
|
531
|
-
// messages: [
|
|
532
|
-
// '请确认以下各项:',
|
|
533
|
-
// ' 1 - 当前环境是否开启了匿名登录',
|
|
534
|
-
// ' 2 - 调用 auth().signInAnonymously() 的语法或参数是否正确',
|
|
535
|
-
// `如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
|
|
536
|
-
// ],
|
|
537
|
-
// })
|
|
538
|
-
// public async signInAnonymously(data: {
|
|
539
|
-
// provider_token?: string
|
|
540
|
-
// } = {},): Promise<LoginState> {
|
|
541
|
-
// await this.oauthInstance.authApi.signInAnonymously(data)
|
|
542
|
-
// return this.createLoginState()
|
|
543
|
-
// }
|
|
544
|
-
|
|
545
514
|
/**
|
|
546
|
-
*
|
|
547
|
-
*
|
|
548
|
-
* @
|
|
515
|
+
* https://supabase.com/docs/reference/javascript/auth-onauthstatechange
|
|
516
|
+
* Receive a notification every time an auth event happens.
|
|
517
|
+
* @param callback
|
|
518
|
+
* @returns Promise<{ data: { subscription: Subscription }, error: Error | null }>
|
|
549
519
|
*/
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
' 1 - 当前环境是否开启了匿名登录',
|
|
555
|
-
' 2 - 调用 auth().signInAnonymouslyInWx() 的语法或参数是否正确',
|
|
556
|
-
`如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
|
|
557
|
-
],
|
|
558
|
-
})
|
|
559
|
-
public async signInAnonymouslyInWx({
|
|
560
|
-
useWxCloud,
|
|
561
|
-
}: {
|
|
562
|
-
useWxCloud?: boolean
|
|
563
|
-
} = {}): Promise<LoginState> {
|
|
564
|
-
if (!adapterForWxMp.isMatch()) {
|
|
565
|
-
throw Error('wx api undefined')
|
|
520
|
+
onAuthStateChange(callback: OnAuthStateChangeCallback) {
|
|
521
|
+
if (!this.hasListenerSetUp) {
|
|
522
|
+
this.setupListeners()
|
|
523
|
+
this.hasListenerSetUp = true
|
|
566
524
|
}
|
|
567
|
-
const wxInfo = wx.getAccountInfoSync().miniProgram
|
|
568
525
|
|
|
569
|
-
const
|
|
570
|
-
let result: authModels.GrantProviderTokenResponse | undefined = undefined
|
|
571
|
-
let credentials: Credentials | undefined = undefined
|
|
572
|
-
|
|
573
|
-
try {
|
|
574
|
-
result = await this.oauthInstance.authApi.grantProviderToken(
|
|
575
|
-
{
|
|
576
|
-
provider_id: wxInfo?.appId,
|
|
577
|
-
provider_code: code,
|
|
578
|
-
provider_params: {
|
|
579
|
-
provider_code_type: 'open_id',
|
|
580
|
-
appid: wxInfo?.appId,
|
|
581
|
-
},
|
|
582
|
-
},
|
|
583
|
-
useWxCloud,
|
|
584
|
-
)
|
|
526
|
+
const id = Math.random().toString(36)
|
|
585
527
|
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
528
|
+
if (!this.listeners.has(id)) {
|
|
529
|
+
this.listeners.set(id, new Set())
|
|
530
|
+
}
|
|
589
531
|
|
|
590
|
-
|
|
591
|
-
{ provider_token: result.provider_token },
|
|
592
|
-
useWxCloud,
|
|
593
|
-
)
|
|
532
|
+
this.listeners.get(id)!.add(callback)
|
|
594
533
|
|
|
595
|
-
|
|
596
|
-
|
|
534
|
+
// 返回 Subscription 对象
|
|
535
|
+
const subscription = {
|
|
536
|
+
id,
|
|
537
|
+
callback,
|
|
538
|
+
unsubscribe: () => {
|
|
539
|
+
const callbacks = this.listeners.get(id)
|
|
540
|
+
if (callbacks) {
|
|
541
|
+
callbacks.delete(callback)
|
|
542
|
+
if (callbacks.size === 0) {
|
|
543
|
+
this.listeners.delete(id)
|
|
544
|
+
}
|
|
597
545
|
}
|
|
598
|
-
}
|
|
599
|
-
throw error
|
|
600
|
-
}
|
|
546
|
+
},
|
|
601
547
|
}
|
|
602
548
|
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
try {
|
|
607
|
-
await mainFunc(res.code)
|
|
608
|
-
resolve(true)
|
|
609
|
-
} catch (error) {
|
|
610
|
-
reject(error)
|
|
611
|
-
}
|
|
612
|
-
},
|
|
613
|
-
fail: (res: any) => {
|
|
614
|
-
const error = new Error(res?.errMsg)
|
|
615
|
-
;(error as any).code = res?.errno
|
|
616
|
-
reject(error)
|
|
617
|
-
},
|
|
618
|
-
})
|
|
619
|
-
})
|
|
620
|
-
|
|
621
|
-
return this.createLoginState(undefined, { asyncRefreshUser: true })
|
|
549
|
+
return {
|
|
550
|
+
data: { subscription },
|
|
551
|
+
}
|
|
622
552
|
}
|
|
623
553
|
|
|
624
554
|
/**
|
|
625
|
-
*
|
|
626
|
-
*
|
|
627
|
-
* @
|
|
555
|
+
* https://supabase.com/docs/reference/javascript/auth-signinwithpassword
|
|
556
|
+
* Log in an existing user with an email and password or phone and password or username and password.
|
|
557
|
+
* @param params
|
|
558
|
+
* @returns Promise<SignInRes>
|
|
628
559
|
*/
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
throw Error('wx api undefined')
|
|
641
|
-
}
|
|
642
|
-
const wxInfo = wx.getAccountInfoSync().miniProgram
|
|
643
|
-
|
|
644
|
-
const mainFunc = async (code) => {
|
|
645
|
-
let result: authModels.GrantProviderTokenResponse | undefined = undefined
|
|
646
|
-
|
|
647
|
-
try {
|
|
648
|
-
result = await this.oauthInstance.authApi.grantProviderToken({
|
|
649
|
-
provider_id: wxInfo?.appId,
|
|
650
|
-
provider_code: code,
|
|
651
|
-
provider_params: {
|
|
652
|
-
provider_code_type: 'open_id',
|
|
653
|
-
appid: wxInfo?.appId,
|
|
654
|
-
},
|
|
655
|
-
})
|
|
560
|
+
async signInWithPassword(params: SignInWithPasswordReq): Promise<SignInRes> {
|
|
561
|
+
try {
|
|
562
|
+
// 参数校验:username/email/phone三选一,password必填
|
|
563
|
+
this.validateAtLeastOne(
|
|
564
|
+
params,
|
|
565
|
+
[['username'], ['email'], ['phone']],
|
|
566
|
+
'You must provide either username, email, or phone',
|
|
567
|
+
)
|
|
568
|
+
this.validateParams(params, {
|
|
569
|
+
password: { required: true, message: 'Password is required' },
|
|
570
|
+
})
|
|
656
571
|
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
572
|
+
await this.signIn({
|
|
573
|
+
username: params.username || params.email || this.formatPhone(params.phone),
|
|
574
|
+
password: params.password,
|
|
575
|
+
...(params.is_encrypt ? { isEncrypt: true, version: 'v2' } : {}),
|
|
576
|
+
})
|
|
577
|
+
const { data: { session } = {} } = await this.getSession()
|
|
660
578
|
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
579
|
+
return { data: { user: session.user, session }, error: null }
|
|
580
|
+
} catch (error) {
|
|
581
|
+
const authError = new AuthError(error)
|
|
582
|
+
// 优化错误提示:登录失败时提供更友好的排查指引
|
|
583
|
+
if (authError.message?.includes('密码不正确') || authError.message?.includes('password')) {
|
|
584
|
+
console.warn('[CloudBase Auth] 登录失败提示:\n'
|
|
585
|
+
+ ' 1. 请确认用户名/邮箱/手机号是否正确\n'
|
|
586
|
+
+ ' 2. 请确认密码是否正确\n'
|
|
587
|
+
+ ' 3. 如果用户不存在,请先通过 auth.signUp() 注册用户,或在云开发控制台手动创建用户\n'
|
|
588
|
+
+ ' 4. 确认当前环境已开启对应的登录方式(控制台 → 环境 → 登录授权)',)
|
|
664
589
|
}
|
|
590
|
+
return { data: {}, error: authError }
|
|
665
591
|
}
|
|
592
|
+
}
|
|
666
593
|
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
const error = new Error(res?.errMsg)
|
|
679
|
-
;(error as any).code = res?.errno
|
|
680
|
-
reject(error)
|
|
681
|
-
},
|
|
594
|
+
/**
|
|
595
|
+
* https://supabase.com/docs/reference/javascript/auth-signinwithidtoken
|
|
596
|
+
* 第三方平台登录。如果用户不存在,会根据云开发平台-登录方式中对应身份源的登录模式配置,判断是否自动注册
|
|
597
|
+
* @param params
|
|
598
|
+
* @returns Promise<SignInRes>
|
|
599
|
+
*/
|
|
600
|
+
async signInWithIdToken(params: SignInWithIdTokenReq): Promise<SignInRes> {
|
|
601
|
+
try {
|
|
602
|
+
// 参数校验:token必填
|
|
603
|
+
this.validateParams(params, {
|
|
604
|
+
token: { required: true, message: 'Token is required' },
|
|
682
605
|
})
|
|
683
|
-
})
|
|
684
606
|
|
|
685
|
-
|
|
607
|
+
await this.signInWithProvider({
|
|
608
|
+
provider_token: params.token,
|
|
609
|
+
})
|
|
610
|
+
const { data: { session } = {} } = await this.getSession()
|
|
611
|
+
|
|
612
|
+
return { data: { user: session.user, session }, error: null }
|
|
613
|
+
} catch (error) {
|
|
614
|
+
return { data: {}, error: new AuthError(error) }
|
|
615
|
+
}
|
|
686
616
|
}
|
|
687
617
|
|
|
688
618
|
/**
|
|
689
|
-
*
|
|
690
|
-
*
|
|
691
|
-
* @
|
|
619
|
+
* https://supabase.com/docs/reference/javascript/auth-signinwithotp
|
|
620
|
+
* Log in a user using a one-time password (OTP).
|
|
621
|
+
* @param params
|
|
622
|
+
* @returns Promise<SignInWithOtpRes>
|
|
692
623
|
*/
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
`如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
|
|
700
|
-
],
|
|
701
|
-
})
|
|
702
|
-
public async signInWithUnionId(): Promise<LoginState> {
|
|
703
|
-
if (!adapterForWxMp.isMatch()) {
|
|
704
|
-
throw Error('wx api undefined')
|
|
624
|
+
async signInWithOtp(params: SignInWithOtpReq): Promise<SignInWithOtpRes> {
|
|
625
|
+
if (params.options?.shouldCreateUser === undefined || !!params.options?.shouldCreateUser) {
|
|
626
|
+
return this.signUp({
|
|
627
|
+
email: params.email,
|
|
628
|
+
phone: params.phone,
|
|
629
|
+
})
|
|
705
630
|
}
|
|
706
|
-
try {
|
|
707
|
-
await new Promise((resolve, reject) => {
|
|
708
|
-
const wxInfo = wx.getAccountInfoSync().miniProgram
|
|
709
|
-
wx.login({
|
|
710
|
-
success: async (res: { code: string }) => {
|
|
711
|
-
const providerId = wxInfo?.appId
|
|
712
|
-
try {
|
|
713
|
-
const result = await this.oauthInstance.authApi.grantProviderToken({
|
|
714
|
-
provider_code: res.code,
|
|
715
|
-
provider_id: providerId,
|
|
716
|
-
provider_params: {
|
|
717
|
-
provider_code_type: 'union_id',
|
|
718
|
-
appid: wxInfo?.appId,
|
|
719
|
-
},
|
|
720
|
-
})
|
|
721
631
|
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
reject(result)
|
|
726
|
-
return
|
|
727
|
-
}
|
|
632
|
+
try {
|
|
633
|
+
// 参数校验:email或phone必填其一
|
|
634
|
+
this.validateAtLeastOne(params, [['email'], ['phone']], 'You must provide either an email or phone number')
|
|
728
635
|
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
provider_token: providerToken,
|
|
732
|
-
})
|
|
636
|
+
// 第一步:发送验证码并存储 verificationInfo
|
|
637
|
+
const verificationInfo = await this.getVerification(params.email ? { email: params.email } : { phone_number: this.formatPhone(params.phone) },)
|
|
733
638
|
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
})
|
|
749
|
-
})
|
|
639
|
+
return {
|
|
640
|
+
data: {
|
|
641
|
+
user: null,
|
|
642
|
+
session: null,
|
|
643
|
+
// 第二步:等待用户输入验证码(通过 Promise 包装用户输入事件)
|
|
644
|
+
verifyOtp: async ({ token, messageId = verificationInfo.verification_id }): Promise<SignInRes> => this.verifyOtp({
|
|
645
|
+
email: params.email,
|
|
646
|
+
phone: params.phone,
|
|
647
|
+
token,
|
|
648
|
+
messageId,
|
|
649
|
+
}),
|
|
650
|
+
},
|
|
651
|
+
error: null,
|
|
652
|
+
}
|
|
750
653
|
} catch (error) {
|
|
751
|
-
|
|
654
|
+
return { data: {}, error: new AuthError(error) }
|
|
752
655
|
}
|
|
753
|
-
|
|
754
|
-
return this.createLoginState()
|
|
755
656
|
}
|
|
756
657
|
|
|
757
658
|
/**
|
|
758
|
-
*
|
|
759
|
-
* @
|
|
760
|
-
* @
|
|
761
|
-
*/
|
|
762
|
-
// @catchErrorsDecorator({
|
|
763
|
-
// title: '小程序手机号授权登录失败',
|
|
764
|
-
// messages: [
|
|
765
|
-
// '请确认以下各项:',
|
|
766
|
-
// ' 1 - 当前环境是否开启了小程序手机号授权登录',
|
|
767
|
-
// ' 2 - 调用 auth().signInWithPhoneAuth() 的语法或参数是否正确',
|
|
768
|
-
// `如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
|
|
769
|
-
// ],
|
|
770
|
-
// })
|
|
771
|
-
// public async signInWithPhoneAuth({ phoneCode = '' }): Promise<LoginState> {
|
|
772
|
-
// if (!adapterForWxMp.isMatch()) {
|
|
773
|
-
// throw Error('wx api undefined')
|
|
774
|
-
// }
|
|
775
|
-
// const wxInfo = wx.getAccountInfoSync().miniProgram
|
|
776
|
-
// const providerInfo = {
|
|
777
|
-
// provider_params: { provider_code_type: 'phone' },
|
|
778
|
-
// provider_id: wxInfo.appId,
|
|
779
|
-
// }
|
|
780
|
-
|
|
781
|
-
// const { code } = await wx.login()
|
|
782
|
-
// ;(providerInfo as any).provider_code = code
|
|
783
|
-
|
|
784
|
-
// try {
|
|
785
|
-
// let providerToken = await this.oauthInstance.authApi.grantProviderToken(providerInfo)
|
|
786
|
-
// if (providerToken.error_code) {
|
|
787
|
-
// throw providerToken
|
|
788
|
-
// }
|
|
789
|
-
|
|
790
|
-
// providerToken = await this.oauthInstance.authApi.patchProviderToken({
|
|
791
|
-
// provider_token: providerToken.provider_token,
|
|
792
|
-
// provider_id: wxInfo.appId,
|
|
793
|
-
// provider_params: {
|
|
794
|
-
// code: phoneCode,
|
|
795
|
-
// provider_code_type: 'phone',
|
|
796
|
-
// },
|
|
797
|
-
// })
|
|
798
|
-
// if (providerToken.error_code) {
|
|
799
|
-
// throw providerToken
|
|
800
|
-
// }
|
|
801
|
-
|
|
802
|
-
// const signInRes = await this.oauthInstance.authApi.signInWithProvider({
|
|
803
|
-
// provider_token: providerToken.provider_token,
|
|
804
|
-
// })
|
|
805
|
-
|
|
806
|
-
// if ((signInRes as any)?.error_code) {
|
|
807
|
-
// throw signInRes
|
|
808
|
-
// }
|
|
809
|
-
// } catch (error) {
|
|
810
|
-
// throw error
|
|
811
|
-
// }
|
|
812
|
-
|
|
813
|
-
// return this.createLoginState()
|
|
814
|
-
// }
|
|
815
|
-
|
|
816
|
-
/**
|
|
817
|
-
* 小程序短信验证码登陆
|
|
818
|
-
* @returns {Promise<LoginState>}
|
|
819
|
-
* @memberof Auth
|
|
659
|
+
* 校验第三方平台授权登录回调
|
|
660
|
+
* @param params
|
|
661
|
+
* @returns Promise<SignInRes>
|
|
820
662
|
*/
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
messages: [
|
|
824
|
-
'请确认以下各项:',
|
|
825
|
-
' 1 - 当前环境是否开启了小程序短信验证码登陆',
|
|
826
|
-
' 2 - 调用 auth().signInWithSms() 的语法或参数是否正确',
|
|
827
|
-
`如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
|
|
828
|
-
],
|
|
829
|
-
})
|
|
830
|
-
public async signInWithSms({
|
|
831
|
-
verificationInfo = { verification_id: '', is_user: false },
|
|
832
|
-
verificationCode = '',
|
|
833
|
-
phoneNum = '',
|
|
834
|
-
bindInfo = undefined,
|
|
835
|
-
}): Promise<LoginState> {
|
|
663
|
+
async verifyOAuth(params?: VerifyOAuthReq): Promise<VerifyOAuthRes> {
|
|
664
|
+
const data: any = {}
|
|
836
665
|
try {
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
bindInfo,
|
|
841
|
-
username: phoneNum,
|
|
842
|
-
loginType: 'sms',
|
|
843
|
-
})
|
|
844
|
-
} catch (error) {
|
|
845
|
-
throw error
|
|
846
|
-
}
|
|
847
|
-
}
|
|
666
|
+
// 回调至 provider_redirect_uri 地址(url query中携带 授权code,state等参数),此时检查 state 是否符合预期(如 自己设置的 wx_open)
|
|
667
|
+
const code = params?.code || utils.getQuery('code')
|
|
668
|
+
const state = params?.state || utils.getQuery('state')
|
|
848
669
|
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
*/
|
|
854
|
-
@catchErrorsDecorator({
|
|
855
|
-
title: '邮箱验证码登陆',
|
|
856
|
-
messages: [
|
|
857
|
-
'请确认以下各项:',
|
|
858
|
-
' 1 - 当前环境是否开启了邮箱登陆',
|
|
859
|
-
' 2 - 调用 auth().signInWithEmail() 的语法或参数是否正确',
|
|
860
|
-
`如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
|
|
861
|
-
],
|
|
862
|
-
})
|
|
863
|
-
public async signInWithEmail({
|
|
864
|
-
verificationInfo = { verification_id: '', is_user: false },
|
|
865
|
-
verificationCode = '',
|
|
866
|
-
bindInfo = undefined,
|
|
867
|
-
email = '',
|
|
868
|
-
}): Promise<LoginState> {
|
|
869
|
-
try {
|
|
870
|
-
return this.signInWithUsername({
|
|
871
|
-
verificationInfo,
|
|
872
|
-
verificationCode,
|
|
873
|
-
bindInfo,
|
|
874
|
-
username: email,
|
|
875
|
-
loginType: 'email',
|
|
876
|
-
})
|
|
877
|
-
} catch (error) {
|
|
878
|
-
throw error
|
|
879
|
-
}
|
|
880
|
-
}
|
|
670
|
+
// 参数校验:code和state必填
|
|
671
|
+
if (!code) {
|
|
672
|
+
return { data: {}, error: new AuthError({ message: 'Code is required' }) }
|
|
673
|
+
}
|
|
881
674
|
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
* @memberof Auth
|
|
886
|
-
*/
|
|
887
|
-
public setCustomSignFunc(getTickFn: authModels.GetCustomSignTicketFn): void {
|
|
888
|
-
this.oauthInstance.authApi.setCustomSignFunc(getTickFn)
|
|
889
|
-
}
|
|
675
|
+
if (!state) {
|
|
676
|
+
return { data: {}, error: new AuthError({ message: 'State is required' }) }
|
|
677
|
+
}
|
|
890
678
|
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
* @returns {Promise<LoginState>}
|
|
894
|
-
* @memberof Auth
|
|
895
|
-
*/
|
|
896
|
-
// @catchErrorsDecorator({
|
|
897
|
-
// title: '自定义登录失败',
|
|
898
|
-
// messages: [
|
|
899
|
-
// '请确认以下各项:',
|
|
900
|
-
// ' 1 - 当前环境是否开启了自定义登录',
|
|
901
|
-
// ' 2 - 调用 auth().signInWithCustomTicket() 的语法或参数是否正确',
|
|
902
|
-
// ' 3 - ticket 是否归属于当前环境',
|
|
903
|
-
// ' 4 - 创建 ticket 的自定义登录私钥是否过期',
|
|
904
|
-
// `如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
|
|
905
|
-
// ],
|
|
906
|
-
// })
|
|
907
|
-
// public async signInWithCustomTicket(): Promise<LoginState> {
|
|
908
|
-
// await this.oauthInstance.authApi.signInWithCustomTicket()
|
|
909
|
-
// return this.createLoginState()
|
|
910
|
-
// }
|
|
679
|
+
const cacheData = getBrowserSession(state)
|
|
680
|
+
data.type = cacheData?.type
|
|
911
681
|
|
|
912
|
-
|
|
913
|
-
*
|
|
914
|
-
* @param {authModels.SignInRequest} params
|
|
915
|
-
* @returns {Promise<LoginState>}
|
|
916
|
-
* @memberof Auth
|
|
917
|
-
*/
|
|
918
|
-
public async signIn(params: authModels.SignInRequest): Promise<LoginState> {
|
|
919
|
-
await this.oauthInstance.authApi.signIn(params)
|
|
920
|
-
return this.createLoginState(params)
|
|
921
|
-
}
|
|
682
|
+
const provider = params?.provider || cacheData?.provider || utils.getQuery('provider')
|
|
922
683
|
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
// * @returns {Promise<LoginState>}
|
|
927
|
-
// * @memberof Auth
|
|
928
|
-
// */
|
|
929
|
-
// @catchErrorsDecorator({
|
|
930
|
-
// title: '注册失败',
|
|
931
|
-
// messages: [
|
|
932
|
-
// '请确认以下各项:',
|
|
933
|
-
// ' 1 - 当前环境是否开启了指定登录方式',
|
|
934
|
-
// ' 2 - 调用 auth().signUp() 的语法或参数是否正确',
|
|
935
|
-
// `如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
|
|
936
|
-
// ],
|
|
937
|
-
// })
|
|
938
|
-
// public async signUp(params: authModels.SignUpRequest): Promise<any> {
|
|
939
|
-
// await this.oauthInstance.authApi.signUp(params)
|
|
940
|
-
// return this.createLoginState()
|
|
941
|
-
// }
|
|
684
|
+
if (!provider) {
|
|
685
|
+
return { data, error: new AuthError({ message: 'Provider is required' }) }
|
|
686
|
+
}
|
|
942
687
|
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
public async setPassword(params: authModels.SetPasswordRequest): Promise<void> {
|
|
950
|
-
return this.oauthInstance.authApi.setPassword(params)
|
|
951
|
-
}
|
|
688
|
+
// state符合预期,则获取该三方平台token
|
|
689
|
+
const { provider_token: token } = await this.grantProviderToken({
|
|
690
|
+
provider_id: provider,
|
|
691
|
+
provider_redirect_uri: location.origin + location.pathname, // 指定三方平台跳回的 url 地址
|
|
692
|
+
provider_code: code, // 第三方平台跳转回页面时,url param 中携带的 code 参数
|
|
693
|
+
})
|
|
952
694
|
|
|
953
|
-
|
|
954
|
-
* 检测用户名是否已经占用
|
|
955
|
-
* @param username
|
|
956
|
-
*/
|
|
957
|
-
@catchErrorsDecorator({
|
|
958
|
-
title: '获取用户是否被占用失败',
|
|
959
|
-
messages: [
|
|
960
|
-
'请确认以下各项:',
|
|
961
|
-
' 1 - 调用 auth().isUsernameRegistered() 的语法或参数是否正确',
|
|
962
|
-
`如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
|
|
963
|
-
],
|
|
964
|
-
})
|
|
965
|
-
public async isUsernameRegistered(username: string): Promise<boolean> {
|
|
966
|
-
if (typeof username !== 'string') {
|
|
967
|
-
throwError(ERRORS.INVALID_PARAMS, 'username must be a string')
|
|
968
|
-
}
|
|
695
|
+
let res: VerifyOAuthRes
|
|
969
696
|
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
697
|
+
if (cacheData.type === OAUTH_TYPE.BIND_IDENTITY) {
|
|
698
|
+
res = await this.oauthInstance.authApi.toBindIdentity({ provider_token: token, provider, fireEvent: true })
|
|
699
|
+
} else {
|
|
700
|
+
// 通过 provider_token 仅登录或登录并注册(与云开发平台-登录方式-身份源登录模式配置有关)
|
|
701
|
+
res = await this.signInWithIdToken({
|
|
702
|
+
token,
|
|
703
|
+
})
|
|
704
|
+
res.data = { ...data, ...res.data }
|
|
705
|
+
}
|
|
973
706
|
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
printWarn(
|
|
981
|
-
ERRORS.INVALID_OPERATION,
|
|
982
|
-
'current platform\'s storage is asynchronous, please use getLoginState instead',
|
|
707
|
+
const localSearch = new URLSearchParams(location?.search)
|
|
708
|
+
localSearch.delete('code')
|
|
709
|
+
localSearch.delete('state')
|
|
710
|
+
res.data.redirectUrl = addUrlSearch(
|
|
711
|
+
cacheData?.search === undefined ? `?${localSearch.toString()}` : cacheData?.search,
|
|
712
|
+
cacheData?.hash || location.hash,
|
|
983
713
|
)
|
|
984
|
-
|
|
985
|
-
}
|
|
714
|
+
removeBrowserSession(state)
|
|
986
715
|
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
envId: this.config.env,
|
|
991
|
-
cache: this.cache,
|
|
992
|
-
oauthInstance: this.oauthInstance,
|
|
993
|
-
})
|
|
994
|
-
return loginState
|
|
716
|
+
return res
|
|
717
|
+
} catch (error) {
|
|
718
|
+
return { data, error: new AuthError(error) }
|
|
995
719
|
}
|
|
996
|
-
return null
|
|
997
720
|
}
|
|
998
721
|
|
|
999
722
|
/**
|
|
1000
|
-
*
|
|
1001
|
-
*
|
|
723
|
+
* https://supabase.com/docs/reference/javascript/auth-signinwithoauth
|
|
724
|
+
* 生成第三方平台授权 Uri (如微信二维码扫码授权网页)
|
|
725
|
+
* @param params
|
|
726
|
+
* @returns Promise<SignInOAuthRes>
|
|
1002
727
|
*/
|
|
1003
|
-
|
|
1004
|
-
title: '获取本地登录态失败',
|
|
1005
|
-
messages: [
|
|
1006
|
-
'请确认以下各项:',
|
|
1007
|
-
' 1 - 调用 auth().getLoginState() 的语法或参数是否正确',
|
|
1008
|
-
`如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
|
|
1009
|
-
],
|
|
1010
|
-
})
|
|
1011
|
-
public async getLoginState() {
|
|
1012
|
-
let oauthLoginState = null
|
|
1013
|
-
|
|
728
|
+
async signInWithOAuth(params: SignInWithOAuthReq): Promise<SignInOAuthRes> {
|
|
1014
729
|
try {
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
}
|
|
1019
|
-
|
|
1020
|
-
if (oauthLoginState) {
|
|
1021
|
-
const loginState = new LoginState({
|
|
1022
|
-
envId: this.config.env,
|
|
1023
|
-
cache: this.cache,
|
|
1024
|
-
oauthInstance: this.oauthInstance,
|
|
730
|
+
// 参数校验:provider必填
|
|
731
|
+
this.validateParams(params, {
|
|
732
|
+
provider: { required: true, message: 'Provider is required' },
|
|
1025
733
|
})
|
|
1026
|
-
return loginState
|
|
1027
|
-
}
|
|
1028
734
|
|
|
1029
|
-
|
|
1030
|
-
}
|
|
735
|
+
const href = params.options?.redirectTo || location.href
|
|
1031
736
|
|
|
1032
|
-
|
|
1033
|
-
title: '获取用户信息失败',
|
|
1034
|
-
messages: [
|
|
1035
|
-
'请确认以下各项:',
|
|
1036
|
-
' 1 - 是否已登录',
|
|
1037
|
-
' 2 - 调用 auth().getUserInfo() 的语法或参数是否正确',
|
|
1038
|
-
`如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
|
|
1039
|
-
],
|
|
1040
|
-
})
|
|
1041
|
-
public async getUserInfo(): Promise<(authModels.UserInfo & Partial<User>) | null> {
|
|
1042
|
-
return this.getCurrentUser()
|
|
1043
|
-
}
|
|
737
|
+
const urlObject = new URL(href)
|
|
1044
738
|
|
|
1045
|
-
|
|
1046
|
-
title: '获取微搭插件用户信息失败',
|
|
1047
|
-
messages: [
|
|
1048
|
-
'请确认以下各项:',
|
|
1049
|
-
' 1 - 是否已登录',
|
|
1050
|
-
' 2 - 调用 auth().getWedaUserInfo() 的语法或参数是否正确',
|
|
1051
|
-
`如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
|
|
1052
|
-
],
|
|
1053
|
-
})
|
|
1054
|
-
public async getWedaUserInfo(): Promise<any> {
|
|
1055
|
-
return this.oauthInstance.authApi.getWedaUserInfo()
|
|
1056
|
-
}
|
|
739
|
+
const provider_redirect_uri = urlObject.origin + urlObject.pathname
|
|
1057
740
|
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
if (loginState) {
|
|
1061
|
-
await (loginState.user as User).updateUserBasicInfo(params)
|
|
1062
|
-
}
|
|
1063
|
-
return
|
|
1064
|
-
}
|
|
741
|
+
const state = params.options?.state || `prd-${params.provider}-${Math.random().toString(36)
|
|
742
|
+
.slice(2)}`
|
|
1065
743
|
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
console.error('Auth.getAuthHeader API 已废弃')
|
|
1072
|
-
return {}
|
|
1073
|
-
}
|
|
744
|
+
const { uri } = await this.genProviderRedirectUri({
|
|
745
|
+
provider_id: params.provider,
|
|
746
|
+
provider_redirect_uri,
|
|
747
|
+
state,
|
|
748
|
+
})
|
|
1074
749
|
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
* @param {authModels.BindWithProviderRequest} params
|
|
1078
|
-
* @returns {Promise<void>}
|
|
1079
|
-
* @memberof Auth
|
|
1080
|
-
*/
|
|
1081
|
-
@catchErrorsDecorator({
|
|
1082
|
-
title: '绑定第三方登录方式失败',
|
|
1083
|
-
messages: [
|
|
1084
|
-
'请确认以下各项:',
|
|
1085
|
-
' 1 - 调用 auth().bindWithProvider() 的语法或参数是否正确',
|
|
1086
|
-
' 2 - 此账户是否已经绑定此第三方',
|
|
1087
|
-
`如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
|
|
1088
|
-
],
|
|
1089
|
-
})
|
|
1090
|
-
public async bindWithProvider(params: authModels.BindWithProviderRequest): Promise<void> {
|
|
1091
|
-
return this.oauthInstance.authApi.bindWithProvider(params)
|
|
1092
|
-
}
|
|
750
|
+
// 对 URL 进行解码
|
|
751
|
+
const decodedUri = decodeURIComponent(uri)
|
|
1093
752
|
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
* @param {authModels.QueryUserProfileRequest} appended_params
|
|
1097
|
-
* @returns {Promise<authModels.UserProfile>}
|
|
1098
|
-
* @memberof Auth
|
|
1099
|
-
*/
|
|
1100
|
-
public async queryUser(queryObj: authModels.QueryUserProfileRequest): Promise<authModels.QueryUserProfileResponse> {
|
|
1101
|
-
return this.oauthInstance.authApi.queryUserProfile(queryObj)
|
|
1102
|
-
}
|
|
753
|
+
// 合并额外的查询参数
|
|
754
|
+
let finalUri = decodedUri
|
|
1103
755
|
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
756
|
+
if (params.options?.queryParams) {
|
|
757
|
+
const url = new URL(decodedUri)
|
|
758
|
+
Object.entries(params.options.queryParams).forEach(([key, value]) => {
|
|
759
|
+
url.searchParams.set(key, value)
|
|
760
|
+
})
|
|
761
|
+
finalUri = url.toString()
|
|
762
|
+
}
|
|
1111
763
|
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
764
|
+
saveToBrowserSession(state, {
|
|
765
|
+
provider: params.provider,
|
|
766
|
+
search: urlObject.search,
|
|
767
|
+
hash: urlObject.hash,
|
|
768
|
+
type: params.options?.type || OAUTH_TYPE.SIGN_IN,
|
|
769
|
+
})
|
|
1115
770
|
|
|
1116
|
-
|
|
1117
|
-
|
|
771
|
+
if (isBrowser() && !params.options?.skipBrowserRedirect) {
|
|
772
|
+
window.location.assign(finalUri)
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
return { data: { url: finalUri, provider: params.provider }, error: null }
|
|
776
|
+
} catch (error) {
|
|
777
|
+
return { data: {}, error: new AuthError(error) }
|
|
778
|
+
}
|
|
1118
779
|
}
|
|
1119
780
|
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
781
|
+
// https://supabase.com/docs/reference/javascript/auth-getclaims
|
|
782
|
+
async getClaims(): Promise<GetClaimsRes> {
|
|
783
|
+
try {
|
|
784
|
+
const { accessToken } = await this.getAccessToken()
|
|
785
|
+
const parsedToken = weAppJwtDecodeAll(accessToken)
|
|
786
|
+
return { data: parsedToken, error: null }
|
|
787
|
+
} catch (error) {
|
|
788
|
+
return { data: {}, error: new AuthError(error) }
|
|
789
|
+
}
|
|
1123
790
|
}
|
|
1124
791
|
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
792
|
+
/**
|
|
793
|
+
* https://supabase.com/docs/reference/javascript/auth-resetpasswordforemail
|
|
794
|
+
* 通过 email 或手机号重置密码
|
|
795
|
+
* @param emailOrPhone 邮箱或手机号
|
|
796
|
+
* @returns Promise<ResetPasswordForEmailRes>
|
|
797
|
+
*/
|
|
798
|
+
async resetPasswordForEmail(
|
|
799
|
+
emailOrPhone: string,
|
|
800
|
+
options?: { redirectTo?: string },
|
|
801
|
+
): Promise<ResetPasswordForEmailRes> {
|
|
802
|
+
try {
|
|
803
|
+
// 参数校验:emailOrPhone必填
|
|
804
|
+
this.validateParams(
|
|
805
|
+
{ emailOrPhone },
|
|
806
|
+
{
|
|
807
|
+
emailOrPhone: { required: true, message: 'Email or phone is required' },
|
|
808
|
+
},
|
|
809
|
+
)
|
|
1129
810
|
|
|
1130
|
-
|
|
1131
|
-
await this.oauthInstance.authApi.grantToken(params)
|
|
1132
|
-
return this.createLoginState()
|
|
1133
|
-
}
|
|
811
|
+
const { redirectTo } = options || {}
|
|
1134
812
|
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
813
|
+
// 判断是邮箱还是手机号
|
|
814
|
+
const isEmail = emailOrPhone.includes('@')
|
|
815
|
+
let verificationParams: { email?: string; phone_number?: string }
|
|
1138
816
|
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
817
|
+
if (isEmail) {
|
|
818
|
+
verificationParams = { email: emailOrPhone }
|
|
819
|
+
} else {
|
|
820
|
+
// 正规化手机号
|
|
821
|
+
const formattedPhone = this.formatPhone(emailOrPhone)
|
|
822
|
+
verificationParams = { phone_number: formattedPhone }
|
|
823
|
+
}
|
|
1142
824
|
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
}
|
|
825
|
+
// 第一步:发送验证码并存储 verificationInfo
|
|
826
|
+
const verificationInfo = await this.getVerification(verificationParams)
|
|
1146
827
|
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
828
|
+
return {
|
|
829
|
+
data: {
|
|
830
|
+
// 第二步:等待用户输入验证码(通过 Promise 包装用户输入事件)
|
|
831
|
+
updateUser: async (attributes: UpdateUserAttributes): Promise<SignInRes> => {
|
|
832
|
+
this.validateParams(attributes, {
|
|
833
|
+
nonce: { required: true, message: 'Nonce is required' },
|
|
834
|
+
password: { required: true, message: 'Password is required' },
|
|
835
|
+
})
|
|
836
|
+
try {
|
|
837
|
+
// 第三步:待用户输入完验证码之后,验证验证码
|
|
838
|
+
const verificationTokenRes = await this.verify({
|
|
839
|
+
verification_id: verificationInfo.verification_id,
|
|
840
|
+
verification_code: attributes.nonce,
|
|
841
|
+
})
|
|
1150
842
|
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
843
|
+
await this.oauthInstance.authApi.resetPassword({
|
|
844
|
+
email: isEmail ? emailOrPhone : undefined,
|
|
845
|
+
phone_number: !isEmail ? emailOrPhone : undefined,
|
|
846
|
+
new_password: attributes.password,
|
|
847
|
+
verification_token: verificationTokenRes.verification_token,
|
|
848
|
+
})
|
|
1154
849
|
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
850
|
+
this.config.eventBus?.fire(EVENTS.AUTH_STATE_CHANGED, {
|
|
851
|
+
event: AUTH_STATE_CHANGED_TYPE.PASSWORD_RECOVERY,
|
|
852
|
+
})
|
|
1158
853
|
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
854
|
+
const res = await this.signInWithPassword({
|
|
855
|
+
email: isEmail ? emailOrPhone : undefined,
|
|
856
|
+
phone: !isEmail ? emailOrPhone : undefined,
|
|
857
|
+
password: attributes.password,
|
|
858
|
+
})
|
|
1162
859
|
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
860
|
+
if (redirectTo && isBrowser()) {
|
|
861
|
+
window.location.assign(redirectTo)
|
|
862
|
+
}
|
|
1166
863
|
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
864
|
+
return res
|
|
865
|
+
} catch (error) {
|
|
866
|
+
return { data: {}, error: new AuthError(error) }
|
|
867
|
+
}
|
|
868
|
+
},
|
|
869
|
+
},
|
|
870
|
+
error: null,
|
|
871
|
+
}
|
|
872
|
+
} catch (error) {
|
|
873
|
+
return { data: {}, error: new AuthError(error) }
|
|
874
|
+
}
|
|
1176
875
|
}
|
|
1177
876
|
|
|
1178
877
|
/**
|
|
1179
|
-
*
|
|
1180
|
-
* @param
|
|
878
|
+
* 通过旧密码重置密码
|
|
879
|
+
* @param new_password
|
|
880
|
+
* @param old_password
|
|
1181
881
|
* @returns
|
|
1182
882
|
*/
|
|
1183
|
-
|
|
1184
|
-
|
|
883
|
+
async resetPasswordForOld(params: ResetPasswordForOldReq) {
|
|
884
|
+
try {
|
|
885
|
+
await this.oauthInstance.authApi.updatePasswordByOld({
|
|
886
|
+
old_password: params.old_password,
|
|
887
|
+
new_password: params.new_password,
|
|
888
|
+
})
|
|
889
|
+
|
|
890
|
+
const { data: { session } = {} } = await this.getSession()
|
|
891
|
+
|
|
892
|
+
return { data: { user: session.user, session }, error: null }
|
|
893
|
+
} catch (error) {
|
|
894
|
+
return { data: {}, error: new AuthError(error) }
|
|
895
|
+
}
|
|
1185
896
|
}
|
|
1186
897
|
|
|
1187
898
|
/**
|
|
1188
|
-
*
|
|
1189
|
-
*
|
|
899
|
+
* https://supabase.com/docs/reference/javascript/auth-verifyotp
|
|
900
|
+
* Log in a user given a User supplied OTP and verificationId received through mobile or email.
|
|
901
|
+
* @param params
|
|
902
|
+
* @returns Promise<SignInRes>
|
|
1190
903
|
*/
|
|
1191
|
-
|
|
1192
|
-
|
|
904
|
+
async verifyOtp(params: VerifyOtpReq): Promise<SignInRes> {
|
|
905
|
+
try {
|
|
906
|
+
const { type } = params
|
|
907
|
+
// 参数校验:token和verificationInfo必填
|
|
908
|
+
this.validateParams(params, {
|
|
909
|
+
token: { required: true, message: 'Token is required' },
|
|
910
|
+
messageId: { required: true, message: 'messageId is required' },
|
|
911
|
+
})
|
|
912
|
+
|
|
913
|
+
if (['phone_change', 'email_change'].includes(type)) {
|
|
914
|
+
await this.verify({
|
|
915
|
+
verification_id: params.messageId,
|
|
916
|
+
verification_code: params.token,
|
|
917
|
+
})
|
|
918
|
+
} else {
|
|
919
|
+
await this.signInWithUsername({
|
|
920
|
+
verificationInfo: { verification_id: params.messageId, is_user: true },
|
|
921
|
+
verificationCode: params.token,
|
|
922
|
+
username: params.email || this.formatPhone(params.phone) || '',
|
|
923
|
+
loginType: params.email ? 'email' : 'phone',
|
|
924
|
+
})
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
const { data: { session } = {} } = await this.getSession()
|
|
928
|
+
|
|
929
|
+
return { data: { user: session.user, session }, error: null }
|
|
930
|
+
} catch (error) {
|
|
931
|
+
return { data: {}, error: new AuthError(error) }
|
|
932
|
+
}
|
|
1193
933
|
}
|
|
934
|
+
|
|
1194
935
|
/**
|
|
1195
|
-
*
|
|
936
|
+
* https://supabase.com/docs/reference/javascript/auth-getSession
|
|
937
|
+
* Returns the session, refreshing it if necessary.
|
|
938
|
+
* @returns Promise<SignInRes>
|
|
1196
939
|
*/
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
@catchErrorsDecorator({
|
|
1202
|
-
title: '获取身份源类型',
|
|
1203
|
-
messages: [
|
|
1204
|
-
'请确认以下各项:',
|
|
1205
|
-
' 1 - 调用 auth().getProviderSubType() 的语法或参数是否正确',
|
|
1206
|
-
`如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
|
|
1207
|
-
],
|
|
1208
|
-
})
|
|
1209
|
-
public async getProviderSubType(): Promise<authModels.ProviderSubType> {
|
|
1210
|
-
return this.oauthInstance.authApi.getProviderSubType()
|
|
1211
|
-
}
|
|
940
|
+
async getSession(): Promise<SignInRes> {
|
|
941
|
+
try {
|
|
942
|
+
const credentials: Credentials = await this.oauthInstance.oauth2client.getCredentials()
|
|
1212
943
|
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
944
|
+
if (!credentials || credentials.scope === 'accessKey') {
|
|
945
|
+
return { data: { session: null }, error: null }
|
|
946
|
+
}
|
|
1216
947
|
|
|
1217
|
-
|
|
1218
|
-
return this.oauthInstance.authApi.verifyCaptchaData(params)
|
|
1219
|
-
}
|
|
948
|
+
const { data: { user } = {} } = await this.getUser()
|
|
1220
949
|
|
|
1221
|
-
|
|
1222
|
-
|
|
950
|
+
return { data: { session: { ...credentials, user }, user }, error: null }
|
|
951
|
+
} catch (error) {
|
|
952
|
+
return { data: {}, error: new AuthError(error) }
|
|
953
|
+
}
|
|
1223
954
|
}
|
|
1224
955
|
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
956
|
+
/**
|
|
957
|
+
* https://supabase.com/docs/reference/javascript/auth-refreshsession
|
|
958
|
+
* 无论过期状态如何,都返回一个新的会话
|
|
959
|
+
* @param refresh_token
|
|
960
|
+
* @returns Promise<SignInRes>
|
|
961
|
+
*/
|
|
962
|
+
async refreshSession(refresh_token?: string): Promise<SignInRes> {
|
|
963
|
+
try {
|
|
964
|
+
const credentials: Credentials = await this.oauthInstance.oauth2client.localCredentials.getCredentials()
|
|
965
|
+
credentials.refresh_token = refresh_token || credentials.refresh_token
|
|
966
|
+
const newTokens = await this.oauthInstance.oauth2client.refreshToken(credentials)
|
|
967
|
+
const { data: { user } = {} } = await this.getUser()
|
|
1228
968
|
|
|
1229
|
-
|
|
1230
|
-
|
|
969
|
+
return { data: { user, session: { ...newTokens, user } }, error: null }
|
|
970
|
+
} catch (error) {
|
|
971
|
+
return { data: {}, error: new AuthError(error) }
|
|
972
|
+
}
|
|
1231
973
|
}
|
|
1232
974
|
|
|
1233
|
-
|
|
1234
|
-
|
|
975
|
+
/**
|
|
976
|
+
* https://supabase.com/docs/reference/javascript/auth-getuser
|
|
977
|
+
* 如果存在现有会话,则获取当前用户详细信息
|
|
978
|
+
* @returns Promise<GetUserRes>
|
|
979
|
+
*/
|
|
980
|
+
async getUser(): Promise<GetUserRes> {
|
|
981
|
+
try {
|
|
982
|
+
const user = this.convertToUser(await this.getCurrentUser())
|
|
983
|
+
return { data: { user }, error: null }
|
|
984
|
+
} catch (error) {
|
|
985
|
+
return { data: {}, error: new AuthError(error) }
|
|
986
|
+
}
|
|
1235
987
|
}
|
|
1236
988
|
|
|
1237
|
-
|
|
1238
|
-
|
|
989
|
+
/**
|
|
990
|
+
* 刷新用户信息
|
|
991
|
+
* @returns Promise<CommonRes>
|
|
992
|
+
*/
|
|
993
|
+
async refreshUser(): Promise<CommonRes> {
|
|
994
|
+
try {
|
|
995
|
+
await this.currentUser.refresh()
|
|
996
|
+
|
|
997
|
+
const { data: { session } = {} } = await this.getSession()
|
|
998
|
+
return { data: { user: session.user, session }, error: null }
|
|
999
|
+
} catch (error) {
|
|
1000
|
+
return { data: {}, error: new AuthError(error) }
|
|
1001
|
+
}
|
|
1239
1002
|
}
|
|
1240
1003
|
|
|
1241
1004
|
/**
|
|
1242
|
-
*
|
|
1005
|
+
* https://supabase.com/docs/reference/javascript/auth-updateuser
|
|
1006
|
+
* 更新用户信息
|
|
1007
|
+
* @param params
|
|
1008
|
+
* @returns Promise<GetUserRes | UpdateUserWithVerificationRes>
|
|
1243
1009
|
*/
|
|
1244
|
-
|
|
1245
|
-
verificationInfo = { verification_id: '', is_user: false },
|
|
1246
|
-
verificationCode = '',
|
|
1247
|
-
username: rawUsername = '',
|
|
1248
|
-
bindInfo = undefined,
|
|
1249
|
-
loginType = '',
|
|
1250
|
-
}: {
|
|
1251
|
-
verificationInfo?: authModels.GetVerificationResponse
|
|
1252
|
-
verificationCode?: string
|
|
1253
|
-
username?: string
|
|
1254
|
-
bindInfo?: any
|
|
1255
|
-
loginType?: string
|
|
1256
|
-
}): Promise<LoginState> {
|
|
1010
|
+
async updateUser(params: UpdateUserReq): Promise<GetUserRes | UpdateUserWithVerificationRes> {
|
|
1257
1011
|
try {
|
|
1258
|
-
//
|
|
1259
|
-
const
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
})
|
|
1263
|
-
|
|
1264
|
-
if ((verifyRes as any)?.error_code) {
|
|
1265
|
-
throw verifyRes
|
|
1012
|
+
// 参数校验:至少有一个更新字段被提供
|
|
1013
|
+
const hasValue = Object.keys(params).some(key => params[key] !== undefined && params[key] !== null && params[key] !== '',)
|
|
1014
|
+
if (!hasValue) {
|
|
1015
|
+
throw new AuthError({ message: 'At least one field must be provided for update' })
|
|
1266
1016
|
}
|
|
1267
1017
|
|
|
1268
|
-
|
|
1269
|
-
const { verification_token } = verifyRes
|
|
1018
|
+
const { email, phone, ...restParams } = params
|
|
1270
1019
|
|
|
1271
|
-
//
|
|
1272
|
-
|
|
1273
|
-
|
|
1020
|
+
// 检查是否需要更新 email 或 phone
|
|
1021
|
+
const needsEmailVerification = email !== undefined
|
|
1022
|
+
const needsPhoneVerification = phone !== undefined
|
|
1274
1023
|
|
|
1275
|
-
|
|
1276
|
-
if (loginType === 'email') {
|
|
1277
|
-
username = rawUsername
|
|
1278
|
-
signUpParam = { email: username }
|
|
1279
|
-
}
|
|
1024
|
+
let extraRes = {}
|
|
1280
1025
|
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
username,
|
|
1286
|
-
verification_token,
|
|
1287
|
-
})
|
|
1026
|
+
if (needsEmailVerification || needsPhoneVerification) {
|
|
1027
|
+
// 需要发送验证码
|
|
1028
|
+
let verificationParams: { email?: string; phone_number?: string }
|
|
1029
|
+
let verificationType: 'email_change' | 'phone_change'
|
|
1288
1030
|
|
|
1289
|
-
if (
|
|
1290
|
-
|
|
1031
|
+
if (needsEmailVerification) {
|
|
1032
|
+
verificationParams = { email: params.email }
|
|
1033
|
+
verificationType = 'email_change'
|
|
1034
|
+
} else {
|
|
1035
|
+
// 正规化手机号
|
|
1036
|
+
const formattedPhone = this.formatPhone(params.phone)
|
|
1037
|
+
verificationParams = { phone_number: formattedPhone }
|
|
1038
|
+
verificationType = 'phone_change'
|
|
1291
1039
|
}
|
|
1292
1040
|
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
provider_token: (bindInfo as any)?.providerToken,
|
|
1296
|
-
})
|
|
1041
|
+
// 发送验证码
|
|
1042
|
+
const verificationInfo = await this.getVerification(verificationParams)
|
|
1297
1043
|
|
|
1298
|
-
|
|
1299
|
-
throw bindRes
|
|
1300
|
-
}
|
|
1301
|
-
}
|
|
1302
|
-
} else {
|
|
1303
|
-
// 自定义应用走signUp逻辑
|
|
1304
|
-
const signUpRes = await this.oauthInstance.authApi.signUp({
|
|
1305
|
-
...signUpParam,
|
|
1306
|
-
verification_token,
|
|
1307
|
-
provider_token: (bindInfo as any)?.providerId,
|
|
1308
|
-
})
|
|
1044
|
+
Object.keys(restParams).length > 0 && (await this.updateUserBasicInfo(restParams))
|
|
1309
1045
|
|
|
1310
|
-
|
|
1311
|
-
|
|
1046
|
+
extraRes = {
|
|
1047
|
+
messageId: verificationInfo.verification_id,
|
|
1048
|
+
verifyOtp: async (verifyParams: { email?: string; phone?: string; token: string }): Promise<GetUserRes> => {
|
|
1049
|
+
try {
|
|
1050
|
+
if (verifyParams.email && params.email === verifyParams.email) {
|
|
1051
|
+
// 验证码验证
|
|
1052
|
+
await this.verifyOtp({
|
|
1053
|
+
type: 'email_change',
|
|
1054
|
+
email: params.email,
|
|
1055
|
+
token: verifyParams.token,
|
|
1056
|
+
messageId: verificationInfo.verification_id,
|
|
1057
|
+
})
|
|
1058
|
+
await this.updateUserBasicInfo({ email: params.email })
|
|
1059
|
+
} else if (verifyParams.phone && params.phone === verifyParams.phone) {
|
|
1060
|
+
// 验证码验证
|
|
1061
|
+
await this.verifyOtp({
|
|
1062
|
+
type: 'phone_change',
|
|
1063
|
+
phone: params.phone,
|
|
1064
|
+
token: verifyParams.token,
|
|
1065
|
+
messageId: verificationInfo.verification_id,
|
|
1066
|
+
})
|
|
1067
|
+
await this.updateUserBasicInfo({ phone: this.formatPhone(params.phone) })
|
|
1068
|
+
} else {
|
|
1069
|
+
await this.verifyOtp({
|
|
1070
|
+
type: verificationType,
|
|
1071
|
+
email: needsEmailVerification ? params.email : undefined,
|
|
1072
|
+
phone: !needsEmailVerification ? params.phone : undefined,
|
|
1073
|
+
token: verifyParams.token,
|
|
1074
|
+
messageId: verificationInfo.verification_id,
|
|
1075
|
+
})
|
|
1076
|
+
// 验证成功后更新用户信息
|
|
1077
|
+
await this.updateUserBasicInfo(params)
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
const {
|
|
1081
|
+
data: { user },
|
|
1082
|
+
} = await this.getUser()
|
|
1083
|
+
this.config.eventBus?.fire(EVENTS.AUTH_STATE_CHANGED, { event: AUTH_STATE_CHANGED_TYPE.USER_UPDATED })
|
|
1084
|
+
|
|
1085
|
+
return { data: { user }, error: null }
|
|
1086
|
+
} catch (error) {
|
|
1087
|
+
return { data: {}, error: new AuthError(error) }
|
|
1088
|
+
}
|
|
1089
|
+
},
|
|
1312
1090
|
}
|
|
1091
|
+
} else {
|
|
1092
|
+
// 不需要验证,直接更新
|
|
1093
|
+
await this.updateUserBasicInfo(params)
|
|
1313
1094
|
}
|
|
1095
|
+
const {
|
|
1096
|
+
data: { user },
|
|
1097
|
+
} = await this.getUser()
|
|
1098
|
+
this.config.eventBus?.fire(EVENTS.AUTH_STATE_CHANGED, { event: AUTH_STATE_CHANGED_TYPE.USER_UPDATED })
|
|
1314
1099
|
|
|
1315
|
-
return
|
|
1100
|
+
return { data: { user, ...extraRes }, error: null }
|
|
1316
1101
|
} catch (error) {
|
|
1317
|
-
|
|
1102
|
+
return { data: {}, error: new AuthError(error) }
|
|
1318
1103
|
}
|
|
1319
1104
|
}
|
|
1320
1105
|
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
})
|
|
1330
|
-
|
|
1331
|
-
await loginState.checkLocalStateAsync()
|
|
1106
|
+
/**
|
|
1107
|
+
* https://supabase.com/docs/reference/javascript/auth-getuseridentities
|
|
1108
|
+
* 获取所有身份源
|
|
1109
|
+
* @returns Promise<GetUserIdentitiesRes>
|
|
1110
|
+
*/
|
|
1111
|
+
async getUserIdentities(): Promise<GetUserIdentitiesRes> {
|
|
1112
|
+
try {
|
|
1113
|
+
const providers = await this.oauthInstance.authApi.getProviders()
|
|
1332
1114
|
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
} else {
|
|
1339
|
-
await loginState.user.refresh(params)
|
|
1115
|
+
return {
|
|
1116
|
+
data: {
|
|
1117
|
+
identities: providers?.data?.filter(v => !!v.bind) as unknown as GetUserIdentitiesRes['data']['identities'],
|
|
1118
|
+
},
|
|
1119
|
+
error: null,
|
|
1340
1120
|
}
|
|
1121
|
+
} catch (error) {
|
|
1122
|
+
return { data: {}, error: new AuthError(error) }
|
|
1341
1123
|
}
|
|
1124
|
+
}
|
|
1342
1125
|
|
|
1343
|
-
|
|
1126
|
+
/**
|
|
1127
|
+
* https://supabase.com/docs/reference/javascript/auth-linkidentity
|
|
1128
|
+
* 绑定身份源到当前用户
|
|
1129
|
+
* @param params
|
|
1130
|
+
* @returns Promise<LinkIdentityRes>
|
|
1131
|
+
*/
|
|
1132
|
+
async linkIdentity(params: LinkIdentityReq): Promise<LinkIdentityRes> {
|
|
1133
|
+
try {
|
|
1134
|
+
// 参数校验:provider必填
|
|
1135
|
+
this.validateParams(params, {
|
|
1136
|
+
provider: { required: true, message: 'Provider is required' },
|
|
1137
|
+
})
|
|
1344
1138
|
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1139
|
+
await this.signInWithOAuth({
|
|
1140
|
+
provider: params.provider,
|
|
1141
|
+
options: {
|
|
1142
|
+
type: OAUTH_TYPE.BIND_IDENTITY,
|
|
1143
|
+
},
|
|
1144
|
+
})
|
|
1348
1145
|
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
this.oauthInstance.oauth2client.setAccessKeyCredentials({
|
|
1353
|
-
access_token: this.config.accessKey,
|
|
1354
|
-
token_type: 'Bearer',
|
|
1355
|
-
scope: 'accessKey',
|
|
1356
|
-
expires_at: new Date(+new Date() + +new Date()),
|
|
1357
|
-
expires_in: +new Date() + +new Date(),
|
|
1358
|
-
})
|
|
1359
|
-
} catch (error) {
|
|
1360
|
-
console.warn('accessKey error: ', error)
|
|
1361
|
-
}
|
|
1146
|
+
return { data: { provider: params.provider }, error: null }
|
|
1147
|
+
} catch (error) {
|
|
1148
|
+
return { data: {}, error: new AuthError(error) }
|
|
1362
1149
|
}
|
|
1363
1150
|
}
|
|
1364
1151
|
|
|
1365
|
-
// ========== new auth api methods merged below ==========
|
|
1366
|
-
|
|
1367
1152
|
/**
|
|
1368
|
-
* https://supabase.com/docs/reference/javascript/auth-
|
|
1369
|
-
*
|
|
1370
|
-
* const { data, error } = await auth.signInAnonymously();
|
|
1153
|
+
* https://supabase.com/docs/reference/javascript/auth-unlinkidentity
|
|
1154
|
+
* 解绑身份源
|
|
1371
1155
|
* @param params
|
|
1372
|
-
* @returns
|
|
1156
|
+
* @returns Promise<CommonRes>
|
|
1373
1157
|
*/
|
|
1374
|
-
async
|
|
1158
|
+
async unlinkIdentity(params: UnlinkIdentityReq): Promise<CommonRes> {
|
|
1375
1159
|
try {
|
|
1376
|
-
|
|
1377
|
-
|
|
1160
|
+
// 参数校验:provider必填
|
|
1161
|
+
this.validateParams(params, {
|
|
1162
|
+
provider: { required: true, message: 'Provider is required' },
|
|
1163
|
+
})
|
|
1378
1164
|
|
|
1379
|
-
|
|
1165
|
+
await this.oauthInstance.authApi.unbindProvider({ provider_id: params.provider })
|
|
1380
1166
|
|
|
1381
|
-
|
|
1382
|
-
return { ...(loginState as any), data: { user: session.user, session }, error: null }
|
|
1167
|
+
return { data: {}, error: null }
|
|
1383
1168
|
} catch (error) {
|
|
1384
1169
|
return { data: {}, error: new AuthError(error) }
|
|
1385
1170
|
}
|
|
1386
1171
|
}
|
|
1387
1172
|
|
|
1388
1173
|
/**
|
|
1389
|
-
* https://supabase.com/docs/reference/javascript/auth-
|
|
1390
|
-
*
|
|
1391
|
-
* @
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
async signUp(params: authModels.SignUpRequest & { phone?: string }): Promise<SignUpRes> {
|
|
1395
|
-
if (params.phone_number || params.verification_code || params.verification_token || params.provider_token) {
|
|
1396
|
-
params.phone_number = this.formatPhone(params.phone_number)
|
|
1397
|
-
await this.oauthInstance.authApi.signUp(params)
|
|
1398
|
-
return this.createLoginState() as any
|
|
1399
|
-
}
|
|
1174
|
+
* https://supabase.com/docs/reference/javascript/auth-reauthentication
|
|
1175
|
+
* 重新认证
|
|
1176
|
+
* @returns Promise<ReauthenticateRes>
|
|
1177
|
+
*/
|
|
1178
|
+
async reauthenticate(): Promise<ReauthenticateRes> {
|
|
1400
1179
|
try {
|
|
1401
|
-
|
|
1402
|
-
|
|
1180
|
+
const {
|
|
1181
|
+
data: { user },
|
|
1182
|
+
} = await this.getUser()
|
|
1183
|
+
|
|
1184
|
+
this.validateAtLeastOne(user, [['email', 'phone']], 'You must provide either an email or phone number')
|
|
1185
|
+
const userInfo = user.email ? { email: user.email } : { phone_number: this.formatPhone(user.phone) }
|
|
1403
1186
|
|
|
1404
1187
|
// 第一步:发送验证码并存储 verificationInfo
|
|
1405
|
-
const verificationInfo = await this.getVerification(
|
|
1188
|
+
const verificationInfo = await this.getVerification(userInfo)
|
|
1406
1189
|
|
|
1407
1190
|
return {
|
|
1408
1191
|
data: {
|
|
1409
1192
|
// 第二步:等待用户输入验证码(通过 Promise 包装用户输入事件)
|
|
1410
|
-
|
|
1193
|
+
updateUser: async (attributes: UpdateUserAttributes): Promise<SignInRes> => {
|
|
1194
|
+
this.validateParams(attributes, {
|
|
1195
|
+
nonce: { required: true, message: 'Nonce is required' },
|
|
1196
|
+
})
|
|
1411
1197
|
try {
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1198
|
+
if (attributes.password) {
|
|
1199
|
+
// 第三步:待用户输入完验证码之后,验证验证码
|
|
1200
|
+
const verificationTokenRes = await this.verify({
|
|
1201
|
+
verification_id: verificationInfo.verification_id,
|
|
1202
|
+
verification_code: attributes.nonce,
|
|
1203
|
+
})
|
|
1417
1204
|
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
if (verificationInfo.is_user) {
|
|
1421
|
-
await this.signIn({
|
|
1422
|
-
username: params.email || this.formatPhone(params.phone),
|
|
1205
|
+
// 第四步:获取 sudo_token
|
|
1206
|
+
const sudoRes = await this.oauthInstance.authApi.sudo({
|
|
1423
1207
|
verification_token: verificationTokenRes.verification_token,
|
|
1424
1208
|
})
|
|
1425
|
-
} else {
|
|
1426
|
-
// 如果用户不存在,注册用户
|
|
1427
|
-
const data = JSON.parse(JSON.stringify(params))
|
|
1428
|
-
delete data.email
|
|
1429
|
-
delete data.phone
|
|
1430
1209
|
|
|
1431
|
-
await this.oauthInstance.authApi.
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1210
|
+
await this.oauthInstance.authApi.setPassword({
|
|
1211
|
+
new_password: attributes.password,
|
|
1212
|
+
sudo_token: sudoRes.sudo_token,
|
|
1213
|
+
})
|
|
1214
|
+
} else {
|
|
1215
|
+
await this.signInWithUsername({
|
|
1216
|
+
verificationInfo,
|
|
1217
|
+
verificationCode: attributes.nonce,
|
|
1218
|
+
...userInfo,
|
|
1219
|
+
loginType: userInfo.email ? 'email' : 'phone',
|
|
1436
1220
|
})
|
|
1437
|
-
await this.createLoginState()
|
|
1438
1221
|
}
|
|
1439
1222
|
|
|
1440
1223
|
const { data: { session } = {} } = await this.getSession()
|
|
@@ -1453,1009 +1236,1228 @@ class Auth {
|
|
|
1453
1236
|
}
|
|
1454
1237
|
|
|
1455
1238
|
/**
|
|
1456
|
-
* https://supabase.com/docs/reference/javascript/auth-
|
|
1457
|
-
*
|
|
1458
|
-
*
|
|
1239
|
+
* https://supabase.com/docs/reference/javascript/auth-resend
|
|
1240
|
+
* 重新发送验证码
|
|
1459
1241
|
* @param params
|
|
1242
|
+
* @returns Promise<ResendRes>
|
|
1460
1243
|
*/
|
|
1461
|
-
async
|
|
1244
|
+
async resend(params: ResendReq): Promise<ResendRes> {
|
|
1462
1245
|
try {
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
await this.cache.removeStoreAsync(userInfoKey)
|
|
1466
|
-
this.setAccessKey()
|
|
1246
|
+
// 参数校验:email或phone必填其一
|
|
1247
|
+
this.validateAtLeastOne(params, [['email'], ['phone']], 'You must provide either an email or phone number')
|
|
1467
1248
|
|
|
1468
|
-
|
|
1249
|
+
const target = params.type === 'signup' ? 'ANY' : 'USER'
|
|
1250
|
+
const data: { email?: string; phone_number?: string; target: 'USER' | 'ANY' } = { target }
|
|
1251
|
+
if ('email' in params) {
|
|
1252
|
+
data.email = params.email
|
|
1253
|
+
}
|
|
1469
1254
|
|
|
1470
|
-
|
|
1255
|
+
if ('phone' in params) {
|
|
1256
|
+
data.phone_number = this.formatPhone(params.phone)
|
|
1257
|
+
}
|
|
1471
1258
|
|
|
1472
|
-
//
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
return {
|
|
1259
|
+
// 重新发送验证码
|
|
1260
|
+
const { verification_id: verificationId } = await this.oauthInstance.authApi.getVerification(data)
|
|
1261
|
+
|
|
1262
|
+
return {
|
|
1263
|
+
data: { messageId: verificationId },
|
|
1264
|
+
error: null,
|
|
1265
|
+
}
|
|
1266
|
+
} catch (error: any) {
|
|
1267
|
+
return {
|
|
1268
|
+
data: {},
|
|
1269
|
+
error: new AuthError(error),
|
|
1270
|
+
}
|
|
1476
1271
|
}
|
|
1477
1272
|
}
|
|
1478
1273
|
|
|
1479
1274
|
/**
|
|
1480
|
-
* https://supabase.com/docs/reference/javascript/auth-
|
|
1481
|
-
*
|
|
1482
|
-
* @param
|
|
1483
|
-
* @returns Promise<
|
|
1275
|
+
* https://supabase.com/docs/reference/javascript/auth-setsession
|
|
1276
|
+
* 使用access_token和refresh_token来设置会话
|
|
1277
|
+
* @param params
|
|
1278
|
+
* @returns Promise<SignInRes>
|
|
1484
1279
|
*/
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
this.
|
|
1488
|
-
|
|
1489
|
-
|
|
1280
|
+
async setSession(params: SetSessionReq): Promise<SignInRes> {
|
|
1281
|
+
try {
|
|
1282
|
+
this.validateParams(params, {
|
|
1283
|
+
access_token: { required: true, message: 'Access token is required' },
|
|
1284
|
+
refresh_token: { required: true, message: 'Refresh token is required' },
|
|
1285
|
+
})
|
|
1490
1286
|
|
|
1491
|
-
|
|
1287
|
+
await this.oauthInstance.oauth2client.refreshToken(params, { throwError: true })
|
|
1492
1288
|
|
|
1493
|
-
|
|
1494
|
-
this.listeners.set(id, new Set())
|
|
1495
|
-
}
|
|
1289
|
+
const { data: { session } = {} } = await this.getSession()
|
|
1496
1290
|
|
|
1497
|
-
|
|
1291
|
+
this.config.eventBus?.fire(EVENTS.AUTH_STATE_CHANGED, { event: AUTH_STATE_CHANGED_TYPE.SIGNED_IN })
|
|
1498
1292
|
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
callback,
|
|
1503
|
-
unsubscribe: () => {
|
|
1504
|
-
const callbacks = this.listeners.get(id)
|
|
1505
|
-
if (callbacks) {
|
|
1506
|
-
callbacks.delete(callback)
|
|
1507
|
-
if (callbacks.size === 0) {
|
|
1508
|
-
this.listeners.delete(id)
|
|
1509
|
-
}
|
|
1510
|
-
}
|
|
1511
|
-
},
|
|
1293
|
+
return { data: { user: session.user, session }, error: null }
|
|
1294
|
+
} catch (error) {
|
|
1295
|
+
return { data: {}, error: new AuthError(error) }
|
|
1512
1296
|
}
|
|
1297
|
+
}
|
|
1513
1298
|
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1299
|
+
// https://supabase.com/docs/reference/javascript/auth-exchangecodeforsession
|
|
1300
|
+
async exchangeCodeForSession() {
|
|
1301
|
+
//
|
|
1517
1302
|
}
|
|
1518
1303
|
|
|
1519
1304
|
/**
|
|
1520
|
-
*
|
|
1521
|
-
* Log in an existing user with an email and password or phone and password or username and password.
|
|
1305
|
+
* 删除当前用户
|
|
1522
1306
|
* @param params
|
|
1523
|
-
* @returns
|
|
1307
|
+
* @returns
|
|
1524
1308
|
*/
|
|
1525
|
-
async
|
|
1309
|
+
async deleteUser(params: DeleteMeReq): Promise<CommonRes> {
|
|
1526
1310
|
try {
|
|
1527
|
-
// 参数校验:username/email/phone三选一,password必填
|
|
1528
|
-
this.validateAtLeastOne(
|
|
1529
|
-
params,
|
|
1530
|
-
[['username'], ['email'], ['phone']],
|
|
1531
|
-
'You must provide either username, email, or phone',
|
|
1532
|
-
)
|
|
1533
1311
|
this.validateParams(params, {
|
|
1534
1312
|
password: { required: true, message: 'Password is required' },
|
|
1535
1313
|
})
|
|
1536
1314
|
|
|
1537
|
-
await this.
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
}
|
|
1315
|
+
const { sudo_token } = await this.oauthInstance.authApi.sudo(params)
|
|
1316
|
+
|
|
1317
|
+
await this.oauthInstance.authApi.deleteMe({ sudo_token })
|
|
1318
|
+
|
|
1319
|
+
return { data: {}, error: null }
|
|
1320
|
+
} catch (error) {
|
|
1321
|
+
return { data: {}, error: new AuthError(error) }
|
|
1322
|
+
}
|
|
1323
|
+
}
|
|
1324
|
+
|
|
1325
|
+
/**
|
|
1326
|
+
* 跳转系统默认登录页
|
|
1327
|
+
* @returns {Promise<authModels.ToDefaultLoginPage>}
|
|
1328
|
+
* @memberof Auth
|
|
1329
|
+
*/
|
|
1330
|
+
async toDefaultLoginPage(params: authModels.ToDefaultLoginPage = {}): Promise<CommonRes> {
|
|
1331
|
+
try {
|
|
1332
|
+
const configVersion = params.config_version || 'env'
|
|
1333
|
+
const query = Object.keys(params.query || {})
|
|
1334
|
+
.map(key => `${key}=${params.query[key]}`)
|
|
1335
|
+
.join('&')
|
|
1336
|
+
|
|
1337
|
+
if (adapterForWxMp.isMatch()) {
|
|
1338
|
+
wx.navigateTo({ url: `/packages/$wd_system/pages/login/index${query ? `?${query}` : ''}` })
|
|
1339
|
+
} else {
|
|
1340
|
+
const redirectUri = params.redirect_uri || window.location.href
|
|
1341
|
+
const urlObj = new URL(redirectUri)
|
|
1342
|
+
const loginPage = `${urlObj.origin}/__auth/?app_id=${params.app_id || ''}&env_id=${this.config.env}&client_id=${
|
|
1343
|
+
this.config.clientId || this.config.env
|
|
1344
|
+
}&config_version=${configVersion}&redirect_uri=${encodeURIComponent(redirectUri)}${query ? `&${query}` : ''}`
|
|
1345
|
+
window.location.href = loginPage
|
|
1346
|
+
}
|
|
1347
|
+
return { data: {}, error: null }
|
|
1348
|
+
} catch (error) {
|
|
1349
|
+
return { data: {}, error: new AuthError(error) }
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1352
|
+
|
|
1353
|
+
/**
|
|
1354
|
+
* 自定义登录
|
|
1355
|
+
* @param getTickFn () => Promise<string>, 获取自定义登录 ticket 的函数
|
|
1356
|
+
* @returns
|
|
1357
|
+
*/
|
|
1358
|
+
async signInWithCustomTicket(getTickFn?: authModels.GetCustomSignTicketFn): Promise<SignInRes> {
|
|
1359
|
+
if (getTickFn) {
|
|
1360
|
+
this.setCustomSignFunc(getTickFn)
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
try {
|
|
1364
|
+
await this.oauthInstance.authApi.signInWithCustomTicket()
|
|
1365
|
+
const loginState = await this.createLoginState()
|
|
1366
|
+
|
|
1542
1367
|
const { data: { session } = {} } = await this.getSession()
|
|
1543
1368
|
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1369
|
+
// loginState返回是为了兼容v2版本
|
|
1370
|
+
return { ...(loginState as any), data: { user: session.user, session }, error: null }
|
|
1371
|
+
} catch (error) {
|
|
1372
|
+
return { data: {}, error: new AuthError(error) }
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1376
|
+
/**
|
|
1377
|
+
* 小程序openId静默登录
|
|
1378
|
+
* @param params
|
|
1379
|
+
* @returns Promise<SignInRes>
|
|
1380
|
+
*/
|
|
1381
|
+
async signInWithOpenId({ useWxCloud = true } = {}): Promise<SignInRes> {
|
|
1382
|
+
if (!adapterForWxMp.isMatch()) {
|
|
1383
|
+
throw Error('wx api undefined')
|
|
1384
|
+
}
|
|
1385
|
+
const wxInfo = wx.getAccountInfoSync().miniProgram
|
|
1386
|
+
|
|
1387
|
+
const mainFunc = async (code) => {
|
|
1388
|
+
let result: authModels.GrantProviderTokenResponse | undefined = undefined
|
|
1389
|
+
let credentials: Credentials | undefined = undefined
|
|
1390
|
+
|
|
1391
|
+
try {
|
|
1392
|
+
result = await this.oauthInstance.authApi.grantProviderToken(
|
|
1393
|
+
{
|
|
1394
|
+
provider_id: wxInfo?.appId,
|
|
1395
|
+
provider_code: code,
|
|
1396
|
+
provider_params: {
|
|
1397
|
+
provider_code_type: 'open_id',
|
|
1398
|
+
appid: wxInfo?.appId,
|
|
1399
|
+
},
|
|
1400
|
+
},
|
|
1401
|
+
useWxCloud,
|
|
1402
|
+
)
|
|
1403
|
+
|
|
1404
|
+
if ((result as any)?.error_code || !result.provider_token) {
|
|
1405
|
+
throw result
|
|
1406
|
+
}
|
|
1407
|
+
|
|
1408
|
+
credentials = await this.oauthInstance.authApi.signInWithProvider(
|
|
1409
|
+
{ provider_token: result.provider_token },
|
|
1410
|
+
useWxCloud,
|
|
1411
|
+
)
|
|
1412
|
+
|
|
1413
|
+
if ((credentials as any)?.error_code) {
|
|
1414
|
+
throw credentials
|
|
1415
|
+
}
|
|
1416
|
+
} catch (error) {
|
|
1417
|
+
throw error
|
|
1418
|
+
}
|
|
1419
|
+
await this.oauthInstance.oauth2client.setCredentials(credentials as Credentials)
|
|
1547
1420
|
}
|
|
1548
|
-
}
|
|
1549
1421
|
|
|
1550
|
-
/**
|
|
1551
|
-
* https://supabase.com/docs/reference/javascript/auth-signinwithidtoken
|
|
1552
|
-
* 第三方平台登录。如果用户不存在,会根据云开发平台-登录方式中对应身份源的登录模式配置,判断是否自动注册
|
|
1553
|
-
* @param params
|
|
1554
|
-
* @returns Promise<SignInRes>
|
|
1555
|
-
*/
|
|
1556
|
-
async signInWithIdToken(params: SignInWithIdTokenReq): Promise<SignInRes> {
|
|
1557
1422
|
try {
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1423
|
+
await new Promise((resolve, reject) => {
|
|
1424
|
+
wx.login({
|
|
1425
|
+
success: async (res: { code: string }) => {
|
|
1426
|
+
try {
|
|
1427
|
+
await mainFunc(res.code)
|
|
1428
|
+
resolve(true)
|
|
1429
|
+
} catch (error) {
|
|
1430
|
+
reject(error)
|
|
1431
|
+
}
|
|
1432
|
+
},
|
|
1433
|
+
fail: (res: any) => {
|
|
1434
|
+
const error = new Error(res?.errMsg)
|
|
1435
|
+
;(error as any).code = res?.errno
|
|
1436
|
+
reject(error)
|
|
1437
|
+
},
|
|
1438
|
+
})
|
|
1561
1439
|
})
|
|
1562
1440
|
|
|
1563
|
-
await this.
|
|
1564
|
-
|
|
1565
|
-
})
|
|
1441
|
+
const loginState = await this.createLoginState()
|
|
1442
|
+
|
|
1566
1443
|
const { data: { session } = {} } = await this.getSession()
|
|
1567
1444
|
|
|
1568
|
-
|
|
1445
|
+
// loginState返回是为了兼容v2版本
|
|
1446
|
+
return { ...(loginState as any), data: { user: session.user, session }, error: null }
|
|
1569
1447
|
} catch (error) {
|
|
1570
1448
|
return { data: {}, error: new AuthError(error) }
|
|
1571
1449
|
}
|
|
1572
1450
|
}
|
|
1573
1451
|
|
|
1574
1452
|
/**
|
|
1575
|
-
*
|
|
1576
|
-
* Log in a user using a one-time password (OTP).
|
|
1453
|
+
* 小程序手机号授权登录
|
|
1577
1454
|
* @param params
|
|
1578
|
-
* @returns Promise<
|
|
1455
|
+
* @returns Promise<SignInRes>
|
|
1579
1456
|
*/
|
|
1580
|
-
async
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1457
|
+
// async signInWithPhoneAuth({ phoneCode = '', useWxCloud = false }): Promise<SignInRes> {
|
|
1458
|
+
async signInWithPhoneAuth({ phoneCode = '' }): Promise<SignInRes> {
|
|
1459
|
+
// if (!adapterForWxMp.isMatch()) {
|
|
1460
|
+
// return { data: {}, error: new AuthError({ message: 'wx api undefined' }) }
|
|
1461
|
+
// }
|
|
1462
|
+
// const wxInfo = wx.getAccountInfoSync().miniProgram
|
|
1463
|
+
// const providerInfo = {
|
|
1464
|
+
// provider_params: { provider_code_type: 'phone', code: phoneCode, appid: wxInfo.appId },
|
|
1465
|
+
// provider_id: wxInfo.appId,
|
|
1466
|
+
// }
|
|
1467
|
+
|
|
1468
|
+
// const { code } = await wx.login()
|
|
1469
|
+
// ;(providerInfo as any).provider_code = code
|
|
1470
|
+
|
|
1471
|
+
// try {
|
|
1472
|
+
// const providerToken = await this.oauthInstance.authApi.grantProviderToken(providerInfo, useWxCloud)
|
|
1473
|
+
// if (providerToken.error_code) {
|
|
1474
|
+
// throw providerToken
|
|
1475
|
+
// }
|
|
1476
|
+
|
|
1477
|
+
// const signInRes = await this.oauthInstance.authApi.signInWithProvider({
|
|
1478
|
+
// provider_token: providerToken.provider_token,
|
|
1479
|
+
// }, useWxCloud)
|
|
1480
|
+
|
|
1481
|
+
// if ((signInRes as any)?.error_code) {
|
|
1482
|
+
// throw signInRes
|
|
1483
|
+
// }
|
|
1484
|
+
// } catch (error) {
|
|
1485
|
+
// return { data: {}, error: new AuthError(error) }
|
|
1486
|
+
// }
|
|
1487
|
+
|
|
1488
|
+
// const loginState = await this.createLoginState()
|
|
1489
|
+
|
|
1490
|
+
// const { data: { session } = {} } = await this.getSession()
|
|
1491
|
+
|
|
1492
|
+
// // loginState返回是为了兼容v2版本
|
|
1493
|
+
// return { ...(loginState as any), data: { user: session.user, session }, error: null }
|
|
1494
|
+
if (!adapterForWxMp.isMatch()) {
|
|
1495
|
+
return { data: {}, error: new AuthError({ message: 'wx api undefined' }) }
|
|
1496
|
+
}
|
|
1497
|
+
const wxInfo = wx.getAccountInfoSync().miniProgram
|
|
1498
|
+
const providerInfo = {
|
|
1499
|
+
provider_params: { provider_code_type: 'phone' },
|
|
1500
|
+
provider_id: wxInfo.appId,
|
|
1586
1501
|
}
|
|
1587
1502
|
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
this.validateAtLeastOne(params, [['email'], ['phone']], 'You must provide either an email or phone number')
|
|
1503
|
+
const { code } = await wx.login()
|
|
1504
|
+
;(providerInfo as any).provider_code = code
|
|
1591
1505
|
|
|
1592
|
-
|
|
1593
|
-
|
|
1506
|
+
try {
|
|
1507
|
+
let providerToken = await this.oauthInstance.authApi.grantProviderToken(providerInfo)
|
|
1508
|
+
if (providerToken.error_code) {
|
|
1509
|
+
throw providerToken
|
|
1510
|
+
}
|
|
1594
1511
|
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
email: params.email,
|
|
1602
|
-
phone: params.phone,
|
|
1603
|
-
token,
|
|
1604
|
-
messageId,
|
|
1605
|
-
}),
|
|
1512
|
+
providerToken = await this.oauthInstance.authApi.patchProviderToken({
|
|
1513
|
+
provider_token: providerToken.provider_token,
|
|
1514
|
+
provider_id: wxInfo.appId,
|
|
1515
|
+
provider_params: {
|
|
1516
|
+
code: phoneCode,
|
|
1517
|
+
provider_code_type: 'phone',
|
|
1606
1518
|
},
|
|
1607
|
-
|
|
1519
|
+
})
|
|
1520
|
+
if (providerToken.error_code) {
|
|
1521
|
+
throw providerToken
|
|
1608
1522
|
}
|
|
1609
|
-
} catch (error) {
|
|
1610
|
-
return { data: {}, error: new AuthError(error) }
|
|
1611
|
-
}
|
|
1612
|
-
}
|
|
1613
|
-
|
|
1614
|
-
/**
|
|
1615
|
-
* 校验第三方平台授权登录回调
|
|
1616
|
-
* @param params
|
|
1617
|
-
* @returns Promise<SignInRes>
|
|
1618
|
-
*/
|
|
1619
|
-
async verifyOAuth(params?: VerifyOAuthReq): Promise<SignInRes | LinkIdentityRes> {
|
|
1620
|
-
const data: any = {}
|
|
1621
|
-
try {
|
|
1622
|
-
// 回调至 provider_redirect_uri 地址(url query中携带 授权code,state等参数),此时检查 state 是否符合预期(如 自己设置的 wx_open)
|
|
1623
|
-
const code = params?.code || utils.getQuery('code')
|
|
1624
|
-
const state = params?.state || utils.getQuery('state')
|
|
1625
1523
|
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
}
|
|
1524
|
+
const signInRes = await this.oauthInstance.authApi.signInWithProvider({
|
|
1525
|
+
provider_token: providerToken.provider_token,
|
|
1526
|
+
})
|
|
1630
1527
|
|
|
1631
|
-
if (
|
|
1632
|
-
|
|
1528
|
+
if ((signInRes as any)?.error_code) {
|
|
1529
|
+
throw signInRes
|
|
1633
1530
|
}
|
|
1531
|
+
} catch (error) {
|
|
1532
|
+
return { data: {}, error: new AuthError(error) }
|
|
1533
|
+
}
|
|
1634
1534
|
|
|
1635
|
-
|
|
1636
|
-
data.type = cacheData?.type
|
|
1535
|
+
const loginState = await this.createLoginState()
|
|
1637
1536
|
|
|
1638
|
-
|
|
1537
|
+
const { data: { session } = {} } = await this.getSession()
|
|
1639
1538
|
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1539
|
+
// loginState返回是为了兼容v2版本
|
|
1540
|
+
return { ...(loginState as any), data: { user: session.user, session }, error: null }
|
|
1541
|
+
}
|
|
1643
1542
|
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1543
|
+
/**
|
|
1544
|
+
* 绑定手机号
|
|
1545
|
+
* @param phoneNumber
|
|
1546
|
+
* @param phoneCode
|
|
1547
|
+
*/
|
|
1548
|
+
@catchErrorsDecorator({
|
|
1549
|
+
title: '绑定手机号失败',
|
|
1550
|
+
messages: [
|
|
1551
|
+
'请确认以下各项:',
|
|
1552
|
+
' 1 - 调用 auth().bindPhoneNumber() 的语法或参数是否正确',
|
|
1553
|
+
' 2 - 当前环境是否开通了短信验证码登录',
|
|
1554
|
+
`如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
|
|
1555
|
+
],
|
|
1556
|
+
})
|
|
1557
|
+
public async bindPhoneNumber(params: authModels.BindPhoneRequest) {
|
|
1558
|
+
return this.oauthInstance.authApi.editContact(params)
|
|
1559
|
+
}
|
|
1650
1560
|
|
|
1651
|
-
|
|
1561
|
+
/**
|
|
1562
|
+
* 解绑三方绑定
|
|
1563
|
+
* @param loginType
|
|
1564
|
+
*/
|
|
1565
|
+
@catchErrorsDecorator({
|
|
1566
|
+
title: '解除三方绑定失败',
|
|
1567
|
+
messages: [
|
|
1568
|
+
'请确认以下各项:',
|
|
1569
|
+
' 1 - 调用 auth().unbindProvider() 的语法或参数是否正确',
|
|
1570
|
+
' 2 - 当前账户是否已经与此登录方式解绑',
|
|
1571
|
+
`如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
|
|
1572
|
+
],
|
|
1573
|
+
})
|
|
1574
|
+
public async unbindProvider(params: authModels.UnbindProviderRequest): Promise<void> {
|
|
1575
|
+
return this.oauthInstance.authApi.unbindProvider(params)
|
|
1576
|
+
}
|
|
1652
1577
|
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1578
|
+
/**
|
|
1579
|
+
* 更新邮箱地址
|
|
1580
|
+
* @param email
|
|
1581
|
+
* @param sudo_token
|
|
1582
|
+
* @param verification_token
|
|
1583
|
+
*/
|
|
1584
|
+
@catchErrorsDecorator({
|
|
1585
|
+
title: '绑定邮箱地址失败',
|
|
1586
|
+
messages: [
|
|
1587
|
+
'请确认以下各项:',
|
|
1588
|
+
' 1 - 调用 auth().bindEmail() 的语法或参数是否正确',
|
|
1589
|
+
' 2 - 当前环境是否开通了邮箱密码登录',
|
|
1590
|
+
`如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
|
|
1591
|
+
],
|
|
1592
|
+
})
|
|
1593
|
+
public bindEmail(params: authModels.BindEmailRequest) {
|
|
1594
|
+
return this.oauthInstance.authApi.editContact(params)
|
|
1595
|
+
}
|
|
1662
1596
|
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1597
|
+
/**
|
|
1598
|
+
* verify
|
|
1599
|
+
* @param {authModels.VerifyRequest} params
|
|
1600
|
+
* @returns {Promise<authModels.VerifyResponse>}
|
|
1601
|
+
* @memberof User
|
|
1602
|
+
*/
|
|
1603
|
+
@catchErrorsDecorator({
|
|
1604
|
+
title: '验证码验证失败',
|
|
1605
|
+
messages: [
|
|
1606
|
+
'请确认以下各项:',
|
|
1607
|
+
' 1 - 调用 auth().verify() 的语法或参数是否正确',
|
|
1608
|
+
' 2 - 当前环境是否开通了手机验证码/邮箱登录',
|
|
1609
|
+
`如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
|
|
1610
|
+
],
|
|
1611
|
+
})
|
|
1612
|
+
public async verify(params: authModels.VerifyRequest): Promise<authModels.VerifyResponse> {
|
|
1613
|
+
return this.oauthInstance.authApi.verify(params)
|
|
1614
|
+
}
|
|
1671
1615
|
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1616
|
+
/**
|
|
1617
|
+
* 获取验证码
|
|
1618
|
+
* @param {authModels.GetVerificationRequest} params
|
|
1619
|
+
* @returns {Promise<authModels.GetVerificationResponse>}
|
|
1620
|
+
* @memberof User
|
|
1621
|
+
*/
|
|
1622
|
+
@catchErrorsDecorator({
|
|
1623
|
+
title: '获取验证码失败',
|
|
1624
|
+
messages: [
|
|
1625
|
+
'请确认以下各项:',
|
|
1626
|
+
' 1 - 调用 auth().getVerification() 的语法或参数是否正确',
|
|
1627
|
+
' 2 - 当前环境是否开通了手机验证码/邮箱登录',
|
|
1628
|
+
`如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
|
|
1629
|
+
],
|
|
1630
|
+
})
|
|
1631
|
+
public async getVerification(
|
|
1632
|
+
params: authModels.GetVerificationRequest,
|
|
1633
|
+
options?: { withCaptcha: boolean },
|
|
1634
|
+
): Promise<authModels.GetVerificationResponse> {
|
|
1635
|
+
if (params.phone_number) {
|
|
1636
|
+
params.phone_number = this.formatPhone(params.phone_number)
|
|
1675
1637
|
}
|
|
1638
|
+
return this.oauthInstance.authApi.getVerification(params, options)
|
|
1676
1639
|
}
|
|
1677
1640
|
|
|
1678
1641
|
/**
|
|
1679
|
-
*
|
|
1680
|
-
* 生成第三方平台授权 Uri (如微信二维码扫码授权网页)
|
|
1681
|
-
* @param params
|
|
1682
|
-
* @returns Promise<SignInOAuthRes>
|
|
1642
|
+
* 获取当前登录的用户信息-同步
|
|
1683
1643
|
*/
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
//
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1644
|
+
get currentUser() {
|
|
1645
|
+
if (this.cache.mode === 'async') {
|
|
1646
|
+
// async storage的平台调用此API提示
|
|
1647
|
+
printWarn(
|
|
1648
|
+
ERRORS.INVALID_OPERATION,
|
|
1649
|
+
'current platform\'s storage is asynchronous, please use getCurrentUser instead',
|
|
1650
|
+
)
|
|
1651
|
+
return
|
|
1652
|
+
}
|
|
1692
1653
|
|
|
1693
|
-
|
|
1654
|
+
const loginState = this.hasLoginState()
|
|
1694
1655
|
|
|
1695
|
-
|
|
1656
|
+
if (loginState) {
|
|
1657
|
+
return loginState.user || null
|
|
1658
|
+
}
|
|
1659
|
+
return null
|
|
1660
|
+
}
|
|
1696
1661
|
|
|
1697
|
-
|
|
1698
|
-
|
|
1662
|
+
/**
|
|
1663
|
+
* 获取当前登录的用户信息-异步
|
|
1664
|
+
*/
|
|
1665
|
+
@catchErrorsDecorator({
|
|
1666
|
+
title: '获取用户信息失败',
|
|
1667
|
+
messages: [
|
|
1668
|
+
'请确认以下各项:',
|
|
1669
|
+
' 1 - 调用 auth().getCurrentUser() 的语法或参数是否正确',
|
|
1670
|
+
`如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
|
|
1671
|
+
],
|
|
1672
|
+
})
|
|
1673
|
+
public async getCurrentUser(): Promise<(authModels.UserInfo & Partial<User>) | null> {
|
|
1674
|
+
const loginState = await this.getLoginState()
|
|
1675
|
+
if (loginState) {
|
|
1676
|
+
const userInfo = loginState.user.getLocalUserInfo() as authModels.UserInfo
|
|
1677
|
+
await loginState.user.checkLocalInfoAsync()
|
|
1678
|
+
return { ...loginState.user, ...userInfo } as unknown as authModels.UserInfo & Partial<User>
|
|
1679
|
+
}
|
|
1680
|
+
return null
|
|
1681
|
+
}
|
|
1699
1682
|
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1683
|
+
/**
|
|
1684
|
+
* 匿名登录
|
|
1685
|
+
* @returns {Promise<LoginState>}
|
|
1686
|
+
* @memberof Auth
|
|
1687
|
+
*/
|
|
1688
|
+
@catchErrorsDecorator({
|
|
1689
|
+
title: '小程序匿名登录失败',
|
|
1690
|
+
messages: [
|
|
1691
|
+
'请确认以下各项:',
|
|
1692
|
+
' 1 - 当前环境是否开启了匿名登录',
|
|
1693
|
+
' 2 - 调用 auth().signInAnonymouslyInWx() 的语法或参数是否正确',
|
|
1694
|
+
`如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
|
|
1695
|
+
],
|
|
1696
|
+
})
|
|
1697
|
+
public async signInAnonymouslyInWx({
|
|
1698
|
+
useWxCloud,
|
|
1699
|
+
}: {
|
|
1700
|
+
useWxCloud?: boolean
|
|
1701
|
+
} = {}): Promise<LoginState> {
|
|
1702
|
+
if (!adapterForWxMp.isMatch()) {
|
|
1703
|
+
throw Error('wx api undefined')
|
|
1704
|
+
}
|
|
1705
|
+
const wxInfo = wx.getAccountInfoSync().miniProgram
|
|
1705
1706
|
|
|
1706
|
-
|
|
1707
|
-
|
|
1707
|
+
const mainFunc = async (code) => {
|
|
1708
|
+
let result: authModels.GrantProviderTokenResponse | undefined = undefined
|
|
1709
|
+
let credentials: Credentials | undefined = undefined
|
|
1708
1710
|
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
+
try {
|
|
1712
|
+
result = await this.oauthInstance.authApi.grantProviderToken(
|
|
1713
|
+
{
|
|
1714
|
+
provider_id: wxInfo?.appId,
|
|
1715
|
+
provider_code: code,
|
|
1716
|
+
provider_params: {
|
|
1717
|
+
provider_code_type: 'open_id',
|
|
1718
|
+
appid: wxInfo?.appId,
|
|
1719
|
+
},
|
|
1720
|
+
},
|
|
1721
|
+
useWxCloud,
|
|
1722
|
+
)
|
|
1711
1723
|
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
url.searchParams.set(key, value)
|
|
1716
|
-
})
|
|
1717
|
-
finalUri = url.toString()
|
|
1718
|
-
}
|
|
1724
|
+
if ((result as any)?.error_code || !result.provider_token) {
|
|
1725
|
+
throw result
|
|
1726
|
+
}
|
|
1719
1727
|
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
type: params.options?.type || OAUTH_TYPE.SIGN_IN,
|
|
1725
|
-
})
|
|
1728
|
+
credentials = await this.oauthInstance.authApi.signInAnonymously(
|
|
1729
|
+
{ provider_token: result.provider_token },
|
|
1730
|
+
useWxCloud,
|
|
1731
|
+
)
|
|
1726
1732
|
|
|
1727
|
-
|
|
1728
|
-
|
|
1733
|
+
if ((credentials as any)?.error_code) {
|
|
1734
|
+
throw credentials
|
|
1735
|
+
}
|
|
1736
|
+
} catch (error) {
|
|
1737
|
+
throw error
|
|
1729
1738
|
}
|
|
1730
|
-
|
|
1731
|
-
return { data: { url: finalUri, provider: params.provider }, error: null }
|
|
1732
|
-
} catch (error) {
|
|
1733
|
-
return { data: {}, error: new AuthError(error) }
|
|
1734
1739
|
}
|
|
1735
|
-
}
|
|
1736
1740
|
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1741
|
+
await new Promise((resolve, reject) => {
|
|
1742
|
+
wx.login({
|
|
1743
|
+
success: async (res: { code: string }) => {
|
|
1744
|
+
try {
|
|
1745
|
+
await mainFunc(res.code)
|
|
1746
|
+
resolve(true)
|
|
1747
|
+
} catch (error) {
|
|
1748
|
+
reject(error)
|
|
1749
|
+
}
|
|
1750
|
+
},
|
|
1751
|
+
fail: (res: any) => {
|
|
1752
|
+
const error = new Error(res?.errMsg)
|
|
1753
|
+
;(error as any).code = res?.errno
|
|
1754
|
+
reject(error)
|
|
1755
|
+
},
|
|
1756
|
+
})
|
|
1757
|
+
})
|
|
1758
|
+
|
|
1759
|
+
return this.createLoginState(undefined, { asyncRefreshUser: true })
|
|
1746
1760
|
}
|
|
1747
1761
|
|
|
1748
1762
|
/**
|
|
1749
|
-
*
|
|
1750
|
-
*
|
|
1751
|
-
* @
|
|
1752
|
-
* @returns Promise<ResetPasswordForEmailRes>
|
|
1763
|
+
* 小程序绑定OpenID
|
|
1764
|
+
* @returns {Promise<LoginState>}
|
|
1765
|
+
* @memberof Auth
|
|
1753
1766
|
*/
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
)
|
|
1767
|
+
@catchErrorsDecorator({
|
|
1768
|
+
title: '小程序绑定OpenID失败',
|
|
1769
|
+
messages: [
|
|
1770
|
+
'请确认以下各项:',
|
|
1771
|
+
' 1 - 当前环境是否开启了小程序openId静默登录',
|
|
1772
|
+
' 2 - 调用 auth().bindOpenId() 的语法或参数是否正确',
|
|
1773
|
+
`如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
|
|
1774
|
+
],
|
|
1775
|
+
})
|
|
1776
|
+
public async bindOpenId(): Promise<void> {
|
|
1777
|
+
if (!adapterForWxMp.isMatch()) {
|
|
1778
|
+
throw Error('wx api undefined')
|
|
1779
|
+
}
|
|
1780
|
+
const wxInfo = wx.getAccountInfoSync().miniProgram
|
|
1766
1781
|
|
|
1767
|
-
|
|
1782
|
+
const mainFunc = async (code) => {
|
|
1783
|
+
let result: authModels.GrantProviderTokenResponse | undefined = undefined
|
|
1768
1784
|
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1785
|
+
try {
|
|
1786
|
+
result = await this.oauthInstance.authApi.grantProviderToken({
|
|
1787
|
+
provider_id: wxInfo?.appId,
|
|
1788
|
+
provider_code: code,
|
|
1789
|
+
provider_params: {
|
|
1790
|
+
provider_code_type: 'open_id',
|
|
1791
|
+
appid: wxInfo?.appId,
|
|
1792
|
+
},
|
|
1793
|
+
})
|
|
1772
1794
|
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1795
|
+
if ((result as any)?.error_code || !result.provider_token) {
|
|
1796
|
+
throw result
|
|
1797
|
+
}
|
|
1798
|
+
|
|
1799
|
+
await this.oauthInstance.authApi.bindWithProvider({ provider_token: result.provider_token })
|
|
1800
|
+
} catch (error) {
|
|
1801
|
+
throw error
|
|
1779
1802
|
}
|
|
1803
|
+
}
|
|
1780
1804
|
|
|
1781
|
-
|
|
1782
|
-
|
|
1805
|
+
await new Promise((resolve, reject) => {
|
|
1806
|
+
wx.login({
|
|
1807
|
+
success: async (res: { code: string }) => {
|
|
1808
|
+
try {
|
|
1809
|
+
await mainFunc(res.code)
|
|
1810
|
+
resolve(true)
|
|
1811
|
+
} catch (error) {
|
|
1812
|
+
reject(error)
|
|
1813
|
+
}
|
|
1814
|
+
},
|
|
1815
|
+
fail: (res: any) => {
|
|
1816
|
+
const error = new Error(res?.errMsg)
|
|
1817
|
+
;(error as any).code = res?.errno
|
|
1818
|
+
reject(error)
|
|
1819
|
+
},
|
|
1820
|
+
})
|
|
1821
|
+
})
|
|
1783
1822
|
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1823
|
+
return
|
|
1824
|
+
}
|
|
1825
|
+
|
|
1826
|
+
/**
|
|
1827
|
+
* 小程序unionId静默登录
|
|
1828
|
+
* @returns {Promise<LoginState>}
|
|
1829
|
+
* @memberof Auth
|
|
1830
|
+
*/
|
|
1831
|
+
@catchErrorsDecorator({
|
|
1832
|
+
title: '小程序unionId静默登录失败',
|
|
1833
|
+
messages: [
|
|
1834
|
+
'请确认以下各项:',
|
|
1835
|
+
' 1 - 当前环境是否开启了小程序unionId静默登录',
|
|
1836
|
+
' 2 - 调用 auth().signInWithUnionId() 的语法或参数是否正确',
|
|
1837
|
+
`如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
|
|
1838
|
+
],
|
|
1839
|
+
})
|
|
1840
|
+
public async signInWithUnionId(): Promise<LoginState> {
|
|
1841
|
+
if (!adapterForWxMp.isMatch()) {
|
|
1842
|
+
throw Error('wx api undefined')
|
|
1843
|
+
}
|
|
1844
|
+
try {
|
|
1845
|
+
await new Promise((resolve, reject) => {
|
|
1846
|
+
const wxInfo = wx.getAccountInfoSync().miniProgram
|
|
1847
|
+
wx.login({
|
|
1848
|
+
success: async (res: { code: string }) => {
|
|
1849
|
+
const providerId = wxInfo?.appId
|
|
1792
1850
|
try {
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1851
|
+
const result = await this.oauthInstance.authApi.grantProviderToken({
|
|
1852
|
+
provider_code: res.code,
|
|
1853
|
+
provider_id: providerId,
|
|
1854
|
+
provider_params: {
|
|
1855
|
+
provider_code_type: 'union_id',
|
|
1856
|
+
appid: wxInfo?.appId,
|
|
1857
|
+
},
|
|
1797
1858
|
})
|
|
1798
1859
|
|
|
1799
|
-
|
|
1800
|
-
email: isEmail ? emailOrPhone : undefined,
|
|
1801
|
-
phone_number: !isEmail ? emailOrPhone : undefined,
|
|
1802
|
-
new_password: attributes.password,
|
|
1803
|
-
verification_token: verificationTokenRes.verification_token,
|
|
1804
|
-
})
|
|
1860
|
+
const { provider_token: providerToken } = result
|
|
1805
1861
|
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1862
|
+
if (!providerToken) {
|
|
1863
|
+
reject(result)
|
|
1864
|
+
return
|
|
1865
|
+
}
|
|
1809
1866
|
|
|
1810
|
-
const
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
password: attributes.password,
|
|
1867
|
+
const signInRes = await this.oauthInstance.authApi.signInWithProvider({
|
|
1868
|
+
provider_id: providerId,
|
|
1869
|
+
provider_token: providerToken,
|
|
1814
1870
|
})
|
|
1815
1871
|
|
|
1816
|
-
if (
|
|
1817
|
-
|
|
1872
|
+
if ((signInRes as any)?.error_code) {
|
|
1873
|
+
reject(signInRes)
|
|
1874
|
+
return
|
|
1818
1875
|
}
|
|
1819
|
-
|
|
1820
|
-
return res
|
|
1876
|
+
resolve(true)
|
|
1821
1877
|
} catch (error) {
|
|
1822
|
-
|
|
1878
|
+
reject(error)
|
|
1823
1879
|
}
|
|
1824
1880
|
},
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1881
|
+
fail: (res: any) => {
|
|
1882
|
+
const error = new Error(res?.errMsg)
|
|
1883
|
+
;(error as any).code = res?.errno
|
|
1884
|
+
reject(error)
|
|
1885
|
+
},
|
|
1886
|
+
})
|
|
1887
|
+
})
|
|
1828
1888
|
} catch (error) {
|
|
1829
|
-
|
|
1889
|
+
throw error
|
|
1830
1890
|
}
|
|
1891
|
+
|
|
1892
|
+
return this.createLoginState()
|
|
1831
1893
|
}
|
|
1832
1894
|
|
|
1833
1895
|
/**
|
|
1834
|
-
*
|
|
1835
|
-
* @
|
|
1836
|
-
* @
|
|
1837
|
-
* @returns
|
|
1896
|
+
* 小程序短信验证码登陆
|
|
1897
|
+
* @returns {Promise<LoginState>}
|
|
1898
|
+
* @memberof Auth
|
|
1838
1899
|
*/
|
|
1839
|
-
|
|
1900
|
+
@catchErrorsDecorator({
|
|
1901
|
+
title: '短信验证码登陆',
|
|
1902
|
+
messages: [
|
|
1903
|
+
'请确认以下各项:',
|
|
1904
|
+
' 1 - 当前环境是否开启了小程序短信验证码登陆',
|
|
1905
|
+
' 2 - 调用 auth().signInWithSms() 的语法或参数是否正确',
|
|
1906
|
+
`如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
|
|
1907
|
+
],
|
|
1908
|
+
})
|
|
1909
|
+
public async signInWithSms({
|
|
1910
|
+
verificationInfo = { verification_id: '', is_user: false },
|
|
1911
|
+
verificationCode = '',
|
|
1912
|
+
phoneNum = '',
|
|
1913
|
+
bindInfo = undefined,
|
|
1914
|
+
}): Promise<LoginState> {
|
|
1840
1915
|
try {
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1916
|
+
return this.signInWithUsername({
|
|
1917
|
+
verificationInfo,
|
|
1918
|
+
verificationCode,
|
|
1919
|
+
bindInfo,
|
|
1920
|
+
username: phoneNum,
|
|
1921
|
+
loginType: 'sms',
|
|
1844
1922
|
})
|
|
1845
|
-
|
|
1846
|
-
const { data: { session } = {} } = await this.getSession()
|
|
1847
|
-
|
|
1848
|
-
return { data: { user: session.user, session }, error: null }
|
|
1849
1923
|
} catch (error) {
|
|
1850
|
-
|
|
1924
|
+
throw error
|
|
1851
1925
|
}
|
|
1852
1926
|
}
|
|
1853
1927
|
|
|
1854
1928
|
/**
|
|
1855
|
-
*
|
|
1856
|
-
*
|
|
1857
|
-
* @
|
|
1858
|
-
* @returns Promise<SignInRes>
|
|
1929
|
+
* 邮箱验证码登陆
|
|
1930
|
+
* @returns {Promise<LoginState>}
|
|
1931
|
+
* @memberof Auth
|
|
1859
1932
|
*/
|
|
1860
|
-
|
|
1933
|
+
@catchErrorsDecorator({
|
|
1934
|
+
title: '邮箱验证码登陆',
|
|
1935
|
+
messages: [
|
|
1936
|
+
'请确认以下各项:',
|
|
1937
|
+
' 1 - 当前环境是否开启了邮箱登陆',
|
|
1938
|
+
' 2 - 调用 auth().signInWithEmail() 的语法或参数是否正确',
|
|
1939
|
+
`如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
|
|
1940
|
+
],
|
|
1941
|
+
})
|
|
1942
|
+
public async signInWithEmail({
|
|
1943
|
+
verificationInfo = { verification_id: '', is_user: false },
|
|
1944
|
+
verificationCode = '',
|
|
1945
|
+
bindInfo = undefined,
|
|
1946
|
+
email = '',
|
|
1947
|
+
}): Promise<LoginState> {
|
|
1861
1948
|
try {
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1949
|
+
return this.signInWithUsername({
|
|
1950
|
+
verificationInfo,
|
|
1951
|
+
verificationCode,
|
|
1952
|
+
bindInfo,
|
|
1953
|
+
username: email,
|
|
1954
|
+
loginType: 'email',
|
|
1867
1955
|
})
|
|
1868
|
-
|
|
1869
|
-
if (['phone_change', 'email_change'].includes(type)) {
|
|
1870
|
-
await this.verify({
|
|
1871
|
-
verification_id: params.messageId,
|
|
1872
|
-
verification_code: params.token,
|
|
1873
|
-
})
|
|
1874
|
-
} else {
|
|
1875
|
-
await this.signInWithUsername({
|
|
1876
|
-
verificationInfo: { verification_id: params.messageId, is_user: true },
|
|
1877
|
-
verificationCode: params.token,
|
|
1878
|
-
username: params.email || this.formatPhone(params.phone) || '',
|
|
1879
|
-
loginType: params.email ? 'email' : 'phone',
|
|
1880
|
-
})
|
|
1881
|
-
}
|
|
1882
|
-
|
|
1883
|
-
const { data: { session } = {} } = await this.getSession()
|
|
1884
|
-
|
|
1885
|
-
return { data: { user: session.user, session }, error: null }
|
|
1886
1956
|
} catch (error) {
|
|
1887
|
-
|
|
1957
|
+
throw error
|
|
1888
1958
|
}
|
|
1889
1959
|
}
|
|
1890
1960
|
|
|
1891
1961
|
/**
|
|
1892
|
-
*
|
|
1893
|
-
*
|
|
1894
|
-
* @
|
|
1962
|
+
* 设置获取自定义登录 ticket 函数
|
|
1963
|
+
* @param {authModels.GetCustomSignTicketFn} getTickFn
|
|
1964
|
+
* @memberof Auth
|
|
1895
1965
|
*/
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1966
|
+
public setCustomSignFunc(getTickFn: authModels.GetCustomSignTicketFn): void {
|
|
1967
|
+
this.oauthInstance.authApi.setCustomSignFunc(getTickFn)
|
|
1968
|
+
}
|
|
1899
1969
|
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1970
|
+
/**
|
|
1971
|
+
*
|
|
1972
|
+
* @returns {Promise<LoginState>}
|
|
1973
|
+
* @memberof Auth
|
|
1974
|
+
*/
|
|
1975
|
+
// @catchErrorsDecorator({
|
|
1976
|
+
// title: '自定义登录失败',
|
|
1977
|
+
// messages: [
|
|
1978
|
+
// '请确认以下各项:',
|
|
1979
|
+
// ' 1 - 当前环境是否开启了自定义登录',
|
|
1980
|
+
// ' 2 - 调用 auth().signInWithCustomTicket() 的语法或参数是否正确',
|
|
1981
|
+
// ' 3 - ticket 是否归属于当前环境',
|
|
1982
|
+
// ' 4 - 创建 ticket 的自定义登录私钥是否过期',
|
|
1983
|
+
// `如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
|
|
1984
|
+
// ],
|
|
1985
|
+
// })
|
|
1986
|
+
// public async signInWithCustomTicket(): Promise<LoginState> {
|
|
1987
|
+
// await this.oauthInstance.authApi.signInWithCustomTicket()
|
|
1988
|
+
// return this.createLoginState()
|
|
1989
|
+
// }
|
|
1903
1990
|
|
|
1904
|
-
|
|
1991
|
+
/**
|
|
1992
|
+
*
|
|
1993
|
+
* @param {authModels.SignInRequest} params
|
|
1994
|
+
* @returns {Promise<LoginState>}
|
|
1995
|
+
* @memberof Auth
|
|
1996
|
+
*/
|
|
1997
|
+
public async signIn(params: authModels.SignInRequest): Promise<LoginState> {
|
|
1998
|
+
await this.oauthInstance.authApi.signIn(params)
|
|
1999
|
+
return this.createLoginState(params)
|
|
2000
|
+
}
|
|
1905
2001
|
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
2002
|
+
// /**
|
|
2003
|
+
// *
|
|
2004
|
+
// * @param {authModels.SignUpRequest} params
|
|
2005
|
+
// * @returns {Promise<LoginState>}
|
|
2006
|
+
// * @memberof Auth
|
|
2007
|
+
// */
|
|
2008
|
+
// @catchErrorsDecorator({
|
|
2009
|
+
// title: '注册失败',
|
|
2010
|
+
// messages: [
|
|
2011
|
+
// '请确认以下各项:',
|
|
2012
|
+
// ' 1 - 当前环境是否开启了指定登录方式',
|
|
2013
|
+
// ' 2 - 调用 auth().signUp() 的语法或参数是否正确',
|
|
2014
|
+
// `如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
|
|
2015
|
+
// ],
|
|
2016
|
+
// })
|
|
2017
|
+
// public async signUp(params: authModels.SignUpRequest): Promise<any> {
|
|
2018
|
+
// await this.oauthInstance.authApi.signUp(params)
|
|
2019
|
+
// return this.createLoginState()
|
|
2020
|
+
// }
|
|
2021
|
+
|
|
2022
|
+
/**
|
|
2023
|
+
* 设置密码
|
|
2024
|
+
* @param {authModels.SetPasswordRequest} params
|
|
2025
|
+
* @returns {Promise<void>}
|
|
2026
|
+
* @memberof Auth
|
|
2027
|
+
*/
|
|
2028
|
+
public async setPassword(params: authModels.SetPasswordRequest): Promise<void> {
|
|
2029
|
+
return this.oauthInstance.authApi.setPassword(params)
|
|
2030
|
+
}
|
|
2031
|
+
|
|
2032
|
+
/**
|
|
2033
|
+
* 检测用户名是否已经占用
|
|
2034
|
+
* @param username
|
|
2035
|
+
*/
|
|
2036
|
+
@catchErrorsDecorator({
|
|
2037
|
+
title: '获取用户是否被占用失败',
|
|
2038
|
+
messages: [
|
|
2039
|
+
'请确认以下各项:',
|
|
2040
|
+
' 1 - 调用 auth().isUsernameRegistered() 的语法或参数是否正确',
|
|
2041
|
+
`如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
|
|
2042
|
+
],
|
|
2043
|
+
})
|
|
2044
|
+
public async isUsernameRegistered(username: string): Promise<boolean> {
|
|
2045
|
+
if (typeof username !== 'string') {
|
|
2046
|
+
throwError(ERRORS.INVALID_PARAMS, 'username must be a string')
|
|
1909
2047
|
}
|
|
2048
|
+
|
|
2049
|
+
const { exist } = await this.oauthInstance.authApi.checkIfUserExist({ username })
|
|
2050
|
+
return exist
|
|
1910
2051
|
}
|
|
1911
2052
|
|
|
1912
2053
|
/**
|
|
1913
|
-
*
|
|
1914
|
-
* 无论过期状态如何,都返回一个新的会话
|
|
1915
|
-
* @param refresh_token
|
|
1916
|
-
* @returns Promise<SignInRes>
|
|
2054
|
+
* 获取本地登录态-同步
|
|
1917
2055
|
*/
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
2056
|
+
public hasLoginState(): LoginState | null {
|
|
2057
|
+
if (this.cache.mode === 'async') {
|
|
2058
|
+
// async storage的平台调用此API提示
|
|
2059
|
+
printWarn(
|
|
2060
|
+
ERRORS.INVALID_OPERATION,
|
|
2061
|
+
'current platform\'s storage is asynchronous, please use getLoginState instead',
|
|
2062
|
+
)
|
|
2063
|
+
return
|
|
2064
|
+
}
|
|
1924
2065
|
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
2066
|
+
const oauthLoginState = this.oauthInstance?.authApi.hasLoginStateSync()
|
|
2067
|
+
if (oauthLoginState) {
|
|
2068
|
+
const loginState = new LoginState({
|
|
2069
|
+
envId: this.config.env,
|
|
2070
|
+
cache: this.cache,
|
|
2071
|
+
oauthInstance: this.oauthInstance,
|
|
2072
|
+
})
|
|
2073
|
+
return loginState
|
|
1928
2074
|
}
|
|
2075
|
+
return null
|
|
1929
2076
|
}
|
|
1930
2077
|
|
|
1931
2078
|
/**
|
|
1932
|
-
*
|
|
1933
|
-
*
|
|
1934
|
-
* @returns Promise<GetUserRes>
|
|
2079
|
+
* 获取本地登录态-异步
|
|
2080
|
+
* 此API为兼容异步storage的平台
|
|
1935
2081
|
*/
|
|
1936
|
-
|
|
2082
|
+
@catchErrorsDecorator({
|
|
2083
|
+
title: '获取本地登录态失败',
|
|
2084
|
+
messages: [
|
|
2085
|
+
'请确认以下各项:',
|
|
2086
|
+
' 1 - 调用 auth().getLoginState() 的语法或参数是否正确',
|
|
2087
|
+
`如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
|
|
2088
|
+
],
|
|
2089
|
+
})
|
|
2090
|
+
public async getLoginState() {
|
|
2091
|
+
let oauthLoginState = null
|
|
2092
|
+
|
|
1937
2093
|
try {
|
|
1938
|
-
|
|
1939
|
-
return { data: { user }, error: null }
|
|
2094
|
+
oauthLoginState = await this.oauthInstance.authApi.getLoginState()
|
|
1940
2095
|
} catch (error) {
|
|
1941
|
-
return
|
|
2096
|
+
return null
|
|
1942
2097
|
}
|
|
1943
|
-
}
|
|
1944
|
-
|
|
1945
|
-
/**
|
|
1946
|
-
* 刷新用户信息
|
|
1947
|
-
* @returns Promise<CommonRes>
|
|
1948
|
-
*/
|
|
1949
|
-
async refreshUser(): Promise<CommonRes> {
|
|
1950
|
-
try {
|
|
1951
|
-
await this.currentUser.refresh()
|
|
1952
2098
|
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
2099
|
+
if (oauthLoginState) {
|
|
2100
|
+
const loginState = new LoginState({
|
|
2101
|
+
envId: this.config.env,
|
|
2102
|
+
cache: this.cache,
|
|
2103
|
+
oauthInstance: this.oauthInstance,
|
|
2104
|
+
})
|
|
2105
|
+
return loginState
|
|
1957
2106
|
}
|
|
2107
|
+
|
|
2108
|
+
return null
|
|
1958
2109
|
}
|
|
1959
2110
|
|
|
1960
2111
|
/**
|
|
1961
|
-
*
|
|
1962
|
-
*
|
|
1963
|
-
* @param params
|
|
1964
|
-
* @returns Promise<GetUserRes | UpdateUserWithVerificationRes>
|
|
2112
|
+
* @deprecated 使用 getCurrentUser 代替,因为与node-sdk方法名冲突
|
|
2113
|
+
* @returns
|
|
1965
2114
|
*/
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
}
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
const needsPhoneVerification = phone !== undefined
|
|
1979
|
-
|
|
1980
|
-
let extraRes = {}
|
|
1981
|
-
|
|
1982
|
-
if (needsEmailVerification || needsPhoneVerification) {
|
|
1983
|
-
// 需要发送验证码
|
|
1984
|
-
let verificationParams: { email?: string; phone_number?: string }
|
|
1985
|
-
let verificationType: 'email_change' | 'phone_change'
|
|
1986
|
-
|
|
1987
|
-
if (needsEmailVerification) {
|
|
1988
|
-
verificationParams = { email: params.email }
|
|
1989
|
-
verificationType = 'email_change'
|
|
1990
|
-
} else {
|
|
1991
|
-
// 正规化手机号
|
|
1992
|
-
const formattedPhone = this.formatPhone(params.phone)
|
|
1993
|
-
verificationParams = { phone_number: formattedPhone }
|
|
1994
|
-
verificationType = 'phone_change'
|
|
1995
|
-
}
|
|
1996
|
-
|
|
1997
|
-
// 发送验证码
|
|
1998
|
-
const verificationInfo = await this.getVerification(verificationParams)
|
|
1999
|
-
|
|
2000
|
-
Object.keys(restParams).length > 0 && (await this.updateUserBasicInfo(restParams))
|
|
2001
|
-
|
|
2002
|
-
extraRes = {
|
|
2003
|
-
messageId: verificationInfo.verification_id,
|
|
2004
|
-
verifyOtp: async (verifyParams: { email?: string; phone?: string; token: string }): Promise<GetUserRes> => {
|
|
2005
|
-
try {
|
|
2006
|
-
if (verifyParams.email && params.email === verifyParams.email) {
|
|
2007
|
-
// 验证码验证
|
|
2008
|
-
await this.verifyOtp({
|
|
2009
|
-
type: 'email_change',
|
|
2010
|
-
email: params.email,
|
|
2011
|
-
token: verifyParams.token,
|
|
2012
|
-
messageId: verificationInfo.verification_id,
|
|
2013
|
-
})
|
|
2014
|
-
await this.updateUserBasicInfo({ email: params.email })
|
|
2015
|
-
} else if (verifyParams.phone && params.phone === verifyParams.phone) {
|
|
2016
|
-
// 验证码验证
|
|
2017
|
-
await this.verifyOtp({
|
|
2018
|
-
type: 'phone_change',
|
|
2019
|
-
phone: params.phone,
|
|
2020
|
-
token: verifyParams.token,
|
|
2021
|
-
messageId: verificationInfo.verification_id,
|
|
2022
|
-
})
|
|
2023
|
-
await this.updateUserBasicInfo({ phone: this.formatPhone(params.phone) })
|
|
2024
|
-
} else {
|
|
2025
|
-
await this.verifyOtp({
|
|
2026
|
-
type: verificationType,
|
|
2027
|
-
email: needsEmailVerification ? params.email : undefined,
|
|
2028
|
-
phone: !needsEmailVerification ? params.phone : undefined,
|
|
2029
|
-
token: verifyParams.token,
|
|
2030
|
-
messageId: verificationInfo.verification_id,
|
|
2031
|
-
})
|
|
2032
|
-
// 验证成功后更新用户信息
|
|
2033
|
-
await this.updateUserBasicInfo(params)
|
|
2034
|
-
}
|
|
2035
|
-
|
|
2036
|
-
const {
|
|
2037
|
-
data: { user },
|
|
2038
|
-
} = await this.getUser()
|
|
2039
|
-
this.config.eventBus?.fire(EVENTS.AUTH_STATE_CHANGED, { event: AUTH_STATE_CHANGED_TYPE.USER_UPDATED })
|
|
2115
|
+
@catchErrorsDecorator({
|
|
2116
|
+
title: '获取用户信息失败',
|
|
2117
|
+
messages: [
|
|
2118
|
+
'请确认以下各项:',
|
|
2119
|
+
' 1 - 是否已登录',
|
|
2120
|
+
' 2 - 调用 auth().getUserInfo() 的语法或参数是否正确',
|
|
2121
|
+
`如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
|
|
2122
|
+
],
|
|
2123
|
+
})
|
|
2124
|
+
public async getUserInfo(): Promise<(authModels.UserInfo & Partial<User>) | null> {
|
|
2125
|
+
return this.getCurrentUser()
|
|
2126
|
+
}
|
|
2040
2127
|
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
}
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
} = await this.getUser()
|
|
2054
|
-
this.config.eventBus?.fire(EVENTS.AUTH_STATE_CHANGED, { event: AUTH_STATE_CHANGED_TYPE.USER_UPDATED })
|
|
2128
|
+
@catchErrorsDecorator({
|
|
2129
|
+
title: '获取微搭插件用户信息失败',
|
|
2130
|
+
messages: [
|
|
2131
|
+
'请确认以下各项:',
|
|
2132
|
+
' 1 - 是否已登录',
|
|
2133
|
+
' 2 - 调用 auth().getWedaUserInfo() 的语法或参数是否正确',
|
|
2134
|
+
`如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
|
|
2135
|
+
],
|
|
2136
|
+
})
|
|
2137
|
+
public async getWedaUserInfo(): Promise<any> {
|
|
2138
|
+
return this.oauthInstance.authApi.getWedaUserInfo()
|
|
2139
|
+
}
|
|
2055
2140
|
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2141
|
+
public async updateUserBasicInfo(params: authModels.ModifyUserBasicInfoRequest) {
|
|
2142
|
+
const loginState = await this.getLoginState()
|
|
2143
|
+
if (loginState) {
|
|
2144
|
+
await (loginState.user as User).updateUserBasicInfo(params)
|
|
2059
2145
|
}
|
|
2146
|
+
return
|
|
2060
2147
|
}
|
|
2061
2148
|
|
|
2062
2149
|
/**
|
|
2063
|
-
*
|
|
2064
|
-
*
|
|
2065
|
-
* @returns Promise<GetUserIdentitiesRes>
|
|
2150
|
+
* getAuthHeader 兼容处理
|
|
2151
|
+
* 返回空对象
|
|
2066
2152
|
*/
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
return { data: { identities: providers?.data?.filter(v => !!v.bind) as unknown as GetUserIdentitiesRes['data']['identities'] }, error: null }
|
|
2072
|
-
} catch (error) {
|
|
2073
|
-
return { data: {}, error: new AuthError(error) }
|
|
2074
|
-
}
|
|
2153
|
+
public getAuthHeader(): {} {
|
|
2154
|
+
console.error('Auth.getAuthHeader API 已废弃')
|
|
2155
|
+
return {}
|
|
2075
2156
|
}
|
|
2076
2157
|
|
|
2077
2158
|
/**
|
|
2078
|
-
*
|
|
2079
|
-
*
|
|
2080
|
-
* @
|
|
2081
|
-
* @
|
|
2159
|
+
* 为已有账户绑第三方账户
|
|
2160
|
+
* @param {authModels.BindWithProviderRequest} params
|
|
2161
|
+
* @returns {Promise<void>}
|
|
2162
|
+
* @memberof Auth
|
|
2082
2163
|
*/
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
},
|
|
2095
|
-
})
|
|
2096
|
-
|
|
2097
|
-
return { data: { provider: params.provider }, error: null }
|
|
2098
|
-
} catch (error) {
|
|
2099
|
-
return { data: {}, error: new AuthError(error) }
|
|
2100
|
-
}
|
|
2164
|
+
@catchErrorsDecorator({
|
|
2165
|
+
title: '绑定第三方登录方式失败',
|
|
2166
|
+
messages: [
|
|
2167
|
+
'请确认以下各项:',
|
|
2168
|
+
' 1 - 调用 auth().bindWithProvider() 的语法或参数是否正确',
|
|
2169
|
+
' 2 - 此账户是否已经绑定此第三方',
|
|
2170
|
+
`如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
|
|
2171
|
+
],
|
|
2172
|
+
})
|
|
2173
|
+
public async bindWithProvider(params: authModels.BindWithProviderRequest): Promise<void> {
|
|
2174
|
+
return this.oauthInstance.authApi.bindWithProvider(params)
|
|
2101
2175
|
}
|
|
2102
2176
|
|
|
2103
2177
|
/**
|
|
2104
|
-
*
|
|
2105
|
-
*
|
|
2106
|
-
* @
|
|
2107
|
-
* @
|
|
2178
|
+
* 查询用户
|
|
2179
|
+
* @param {authModels.QueryUserProfileRequest} appended_params
|
|
2180
|
+
* @returns {Promise<authModels.UserProfile>}
|
|
2181
|
+
* @memberof Auth
|
|
2108
2182
|
*/
|
|
2109
|
-
async
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
this.validateParams(params, {
|
|
2113
|
-
provider: { required: true, message: 'Provider is required' },
|
|
2114
|
-
})
|
|
2115
|
-
|
|
2116
|
-
await this.oauthInstance.authApi.unbindProvider({ provider_id: params.provider })
|
|
2183
|
+
public async queryUser(queryObj: authModels.QueryUserProfileRequest): Promise<authModels.QueryUserProfileResponse> {
|
|
2184
|
+
return this.oauthInstance.authApi.queryUserProfile(queryObj)
|
|
2185
|
+
}
|
|
2117
2186
|
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2187
|
+
public async getAccessToken() {
|
|
2188
|
+
const oauthAccessTokenRes = await this.oauthInstance.oauth2client.getAccessToken()
|
|
2189
|
+
return {
|
|
2190
|
+
accessToken: oauthAccessTokenRes,
|
|
2191
|
+
env: this.config.env,
|
|
2121
2192
|
}
|
|
2122
2193
|
}
|
|
2123
2194
|
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
* @returns Promise<ReauthenticateRes>
|
|
2128
|
-
*/
|
|
2129
|
-
async reauthenticate(): Promise<ReauthenticateRes> {
|
|
2130
|
-
try {
|
|
2131
|
-
const {
|
|
2132
|
-
data: { user },
|
|
2133
|
-
} = await this.getUser()
|
|
2134
|
-
|
|
2135
|
-
this.validateAtLeastOne(user, [['email', 'phone']], 'You must provide either an email or phone number')
|
|
2136
|
-
const userInfo = user.email ? { email: user.email } : { phone_number: this.formatPhone(user.phone) }
|
|
2137
|
-
|
|
2138
|
-
// 第一步:发送验证码并存储 verificationInfo
|
|
2139
|
-
const verificationInfo = await this.getVerification(userInfo)
|
|
2140
|
-
|
|
2141
|
-
return {
|
|
2142
|
-
data: {
|
|
2143
|
-
// 第二步:等待用户输入验证码(通过 Promise 包装用户输入事件)
|
|
2144
|
-
updateUser: async (attributes: UpdateUserAttributes): Promise<SignInRes> => {
|
|
2145
|
-
this.validateParams(attributes, {
|
|
2146
|
-
nonce: { required: true, message: 'Nonce is required' },
|
|
2147
|
-
})
|
|
2148
|
-
try {
|
|
2149
|
-
if (attributes.password) {
|
|
2150
|
-
// 第三步:待用户输入完验证码之后,验证验证码
|
|
2151
|
-
const verificationTokenRes = await this.verify({
|
|
2152
|
-
verification_id: verificationInfo.verification_id,
|
|
2153
|
-
verification_code: attributes.nonce,
|
|
2154
|
-
})
|
|
2155
|
-
|
|
2156
|
-
// 第四步:获取 sudo_token
|
|
2157
|
-
const sudoRes = await this.oauthInstance.authApi.sudo({
|
|
2158
|
-
verification_token: verificationTokenRes.verification_token,
|
|
2159
|
-
})
|
|
2160
|
-
|
|
2161
|
-
await this.oauthInstance.authApi.setPassword({
|
|
2162
|
-
new_password: attributes.password,
|
|
2163
|
-
sudo_token: sudoRes.sudo_token,
|
|
2164
|
-
})
|
|
2165
|
-
} else {
|
|
2166
|
-
await this.signInWithUsername({
|
|
2167
|
-
verificationInfo,
|
|
2168
|
-
verificationCode: attributes.nonce,
|
|
2169
|
-
...userInfo,
|
|
2170
|
-
loginType: userInfo.email ? 'email' : 'phone',
|
|
2171
|
-
})
|
|
2172
|
-
}
|
|
2195
|
+
public async grantProviderToken(params: authModels.GrantProviderTokenRequest,): Promise<authModels.GrantProviderTokenResponse> {
|
|
2196
|
+
return this.oauthInstance.authApi.grantProviderToken(params)
|
|
2197
|
+
}
|
|
2173
2198
|
|
|
2174
|
-
|
|
2199
|
+
public async patchProviderToken(params: authModels.PatchProviderTokenRequest,): Promise<authModels.PatchProviderTokenResponse> {
|
|
2200
|
+
return this.oauthInstance.authApi.patchProviderToken(params)
|
|
2201
|
+
}
|
|
2175
2202
|
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
}
|
|
2180
|
-
},
|
|
2181
|
-
},
|
|
2182
|
-
error: null,
|
|
2183
|
-
}
|
|
2184
|
-
} catch (error) {
|
|
2185
|
-
return { data: {}, error: new AuthError(error) }
|
|
2186
|
-
}
|
|
2203
|
+
public async signInWithProvider(params: authModels.SignInWithProviderRequest): Promise<LoginState> {
|
|
2204
|
+
await this.oauthInstance.authApi.signInWithProvider(params)
|
|
2205
|
+
return this.createLoginState(params)
|
|
2187
2206
|
}
|
|
2188
2207
|
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
* @returns Promise<ResendRes>
|
|
2194
|
-
*/
|
|
2195
|
-
async resend(params: ResendReq): Promise<ResendRes> {
|
|
2196
|
-
try {
|
|
2197
|
-
// 参数校验:email或phone必填其一
|
|
2198
|
-
this.validateAtLeastOne(params, [['email'], ['phone']], 'You must provide either an email or phone number')
|
|
2208
|
+
public async signInWithWechat(params: any = {}) {
|
|
2209
|
+
await this.oauthInstance.authApi.signInWithWechat(params)
|
|
2210
|
+
return this.createLoginState(params)
|
|
2211
|
+
}
|
|
2199
2212
|
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
}
|
|
2213
|
+
public async grantToken(params: authModels.GrantTokenRequest): Promise<LoginState> {
|
|
2214
|
+
await this.oauthInstance.authApi.grantToken(params)
|
|
2215
|
+
return this.createLoginState()
|
|
2216
|
+
}
|
|
2205
2217
|
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2218
|
+
public async genProviderRedirectUri(params: authModels.GenProviderRedirectUriRequest,): Promise<authModels.GenProviderRedirectUriResponse> {
|
|
2219
|
+
return this.oauthInstance.authApi.genProviderRedirectUri(params)
|
|
2220
|
+
}
|
|
2209
2221
|
|
|
2210
|
-
|
|
2211
|
-
|
|
2222
|
+
public async resetPassword(params: authModels.ResetPasswordRequest): Promise<void> {
|
|
2223
|
+
return this.oauthInstance.authApi.resetPassword(params)
|
|
2224
|
+
}
|
|
2212
2225
|
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
error: null,
|
|
2216
|
-
}
|
|
2217
|
-
} catch (error: any) {
|
|
2218
|
-
return {
|
|
2219
|
-
data: {},
|
|
2220
|
-
error: new AuthError(error),
|
|
2221
|
-
}
|
|
2222
|
-
}
|
|
2226
|
+
public async deviceAuthorize(params: authModels.DeviceAuthorizeRequest): Promise<authModels.DeviceAuthorizeResponse> {
|
|
2227
|
+
return this.oauthInstance.authApi.deviceAuthorize(params)
|
|
2223
2228
|
}
|
|
2224
2229
|
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
* @param params
|
|
2229
|
-
* @returns Promise<SignInRes>
|
|
2230
|
-
*/
|
|
2231
|
-
async setSession(params: SetSessionReq): Promise<SignInRes> {
|
|
2232
|
-
try {
|
|
2233
|
-
this.validateParams(params, {
|
|
2234
|
-
access_token: { required: true, message: 'Access token is required' },
|
|
2235
|
-
refresh_token: { required: true, message: 'Refresh token is required' },
|
|
2236
|
-
})
|
|
2230
|
+
public async sudo(params: authModels.SudoRequest): Promise<authModels.SudoResponse> {
|
|
2231
|
+
return this.oauthInstance.authApi.sudo(params)
|
|
2232
|
+
}
|
|
2237
2233
|
|
|
2238
|
-
|
|
2234
|
+
public async deleteMe(params: authModels.WithSudoRequest): Promise<authModels.UserProfile> {
|
|
2235
|
+
return this.oauthInstance.authApi.deleteMe(params)
|
|
2236
|
+
}
|
|
2239
2237
|
|
|
2240
|
-
|
|
2238
|
+
public async getProviders(): Promise<authModels.ProvidersResponse> {
|
|
2239
|
+
return this.oauthInstance.authApi.getProviders()
|
|
2240
|
+
}
|
|
2241
2241
|
|
|
2242
|
-
|
|
2242
|
+
public async loginScope(): Promise<string> {
|
|
2243
|
+
return this.oauthInstance.authApi.loginScope()
|
|
2244
|
+
}
|
|
2243
2245
|
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
return { data: {}, error: new AuthError(error) }
|
|
2247
|
-
}
|
|
2246
|
+
public async loginGroups(): Promise<string[]> {
|
|
2247
|
+
return this.oauthInstance.authApi.loginGroups()
|
|
2248
2248
|
}
|
|
2249
2249
|
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2250
|
+
public async onLoginStateChanged(callback: Function) {
|
|
2251
|
+
this.config.eventBus?.on(EVENTS.LOGIN_STATE_CHANGED, async (params) => {
|
|
2252
|
+
// getLoginState会重复触发getCredentials,导致死循环,所以getCredentials出错不再出发getLoginState
|
|
2253
|
+
const loginState = params?.data?.eventType !== LOGIN_STATE_CHANGED_TYPE.CREDENTIALS_ERROR ? await this.getLoginState() : {}
|
|
2254
|
+
callback.call(this, { ...params, ...loginState })
|
|
2255
|
+
})
|
|
2256
|
+
// 立刻执行一次回调
|
|
2257
|
+
const loginState = await this.getLoginState()
|
|
2258
|
+
callback.call(this, loginState)
|
|
2253
2259
|
}
|
|
2254
2260
|
|
|
2255
2261
|
/**
|
|
2256
|
-
*
|
|
2262
|
+
* 强制刷新token
|
|
2257
2263
|
* @param params
|
|
2258
2264
|
* @returns
|
|
2259
2265
|
*/
|
|
2260
|
-
async
|
|
2261
|
-
|
|
2262
|
-
this.validateParams(params, {
|
|
2263
|
-
password: { required: true, message: 'Password is required' },
|
|
2264
|
-
})
|
|
2265
|
-
|
|
2266
|
-
const { sudo_token } = await this.oauthInstance.authApi.sudo(params)
|
|
2267
|
-
|
|
2268
|
-
await this.oauthInstance.authApi.deleteMe({ sudo_token })
|
|
2269
|
-
|
|
2270
|
-
return { data: {}, error: null }
|
|
2271
|
-
} catch (error) {
|
|
2272
|
-
return { data: {}, error: new AuthError(error) }
|
|
2273
|
-
}
|
|
2266
|
+
public async refreshTokenForce(params: { version?: string }): Promise<Credentials> {
|
|
2267
|
+
return this.oauthInstance.authApi.refreshTokenForce(params)
|
|
2274
2268
|
}
|
|
2275
2269
|
|
|
2276
2270
|
/**
|
|
2277
|
-
*
|
|
2278
|
-
* @returns
|
|
2279
|
-
* @memberof Auth
|
|
2271
|
+
* 获取身份信息
|
|
2272
|
+
* @returns
|
|
2280
2273
|
*/
|
|
2281
|
-
async
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2274
|
+
public async getCredentials(): Promise<Credentials> {
|
|
2275
|
+
return this.oauthInstance.authApi.getCredentials()
|
|
2276
|
+
}
|
|
2277
|
+
/**
|
|
2278
|
+
* 写入身份信息
|
|
2279
|
+
*/
|
|
2280
|
+
public async setCredentials(credentials: Credentials) {
|
|
2281
|
+
await this.oauthInstance.oauth2client.setCredentials(credentials)
|
|
2282
|
+
}
|
|
2287
2283
|
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2284
|
+
@catchErrorsDecorator({
|
|
2285
|
+
title: '获取身份源类型',
|
|
2286
|
+
messages: [
|
|
2287
|
+
'请确认以下各项:',
|
|
2288
|
+
' 1 - 调用 auth().getProviderSubType() 的语法或参数是否正确',
|
|
2289
|
+
`如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
|
|
2290
|
+
],
|
|
2291
|
+
})
|
|
2292
|
+
public async getProviderSubType(): Promise<authModels.ProviderSubType> {
|
|
2293
|
+
return this.oauthInstance.authApi.getProviderSubType()
|
|
2294
|
+
}
|
|
2295
|
+
|
|
2296
|
+
public async createCaptchaData(params: { state: string; redirect_uri?: string }) {
|
|
2297
|
+
return this.oauthInstance.authApi.createCaptchaData(params)
|
|
2302
2298
|
}
|
|
2303
2299
|
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
* @returns
|
|
2308
|
-
*/
|
|
2309
|
-
async signInWithCustomTicket(getTickFn?: authModels.GetCustomSignTicketFn): Promise<SignInRes> {
|
|
2310
|
-
if (getTickFn) {
|
|
2311
|
-
this.setCustomSignFunc(getTickFn)
|
|
2312
|
-
}
|
|
2300
|
+
public async verifyCaptchaData(params: { token: string; key: string }) {
|
|
2301
|
+
return this.oauthInstance.authApi.verifyCaptchaData(params)
|
|
2302
|
+
}
|
|
2313
2303
|
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2304
|
+
public async getMiniProgramQrCode(params: authModels.GetMiniProgramQrCodeRequest,): Promise<authModels.GetMiniProgramQrCodeResponse> {
|
|
2305
|
+
return this.oauthInstance.authApi.getMiniProgramCode(params)
|
|
2306
|
+
}
|
|
2317
2307
|
|
|
2318
|
-
|
|
2308
|
+
public async getMiniProgramQrCodeStatus(params: authModels.GetMiniProgramQrCodeStatusRequest,): Promise<authModels.GetMiniProgramQrCodeStatusResponse> {
|
|
2309
|
+
return this.oauthInstance.authApi.getMiniProgramQrCodeStatus(params)
|
|
2310
|
+
}
|
|
2319
2311
|
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2312
|
+
public async modifyPassword(params: authModels.ModifyUserBasicInfoRequest): Promise<void> {
|
|
2313
|
+
return this.oauthInstance.authApi.modifyPassword(params)
|
|
2314
|
+
}
|
|
2315
|
+
|
|
2316
|
+
public async modifyPasswordWithoutLogin(params: authModels.ModifyPasswordWithoutLoginRequest): Promise<void> {
|
|
2317
|
+
return this.oauthInstance.authApi.modifyPasswordWithoutLogin(params)
|
|
2318
|
+
}
|
|
2319
|
+
|
|
2320
|
+
public async getUserBehaviorLog(params: authModels.GetUserBehaviorLog): Promise<authModels.GetUserBehaviorLogRes> {
|
|
2321
|
+
return this.oauthInstance.authApi.getUserBehaviorLog(params)
|
|
2325
2322
|
}
|
|
2326
2323
|
|
|
2327
2324
|
/**
|
|
2328
|
-
*
|
|
2329
|
-
* @param params
|
|
2330
|
-
* @returns Promise<SignInRes>
|
|
2325
|
+
* sms/email 验证码登录/注册,逻辑一致收敛
|
|
2331
2326
|
*/
|
|
2332
|
-
async
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2327
|
+
public async signInWithUsername({
|
|
2328
|
+
verificationInfo = { verification_id: '', is_user: false },
|
|
2329
|
+
verificationCode = '',
|
|
2330
|
+
username: rawUsername = '',
|
|
2331
|
+
bindInfo = undefined,
|
|
2332
|
+
loginType = '',
|
|
2333
|
+
}: {
|
|
2334
|
+
verificationInfo?: authModels.GetVerificationResponse
|
|
2335
|
+
verificationCode?: string
|
|
2336
|
+
username?: string
|
|
2337
|
+
bindInfo?: any
|
|
2338
|
+
loginType?: string
|
|
2339
|
+
}): Promise<LoginState> {
|
|
2340
|
+
try {
|
|
2341
|
+
// 1. 验证验证码
|
|
2342
|
+
const verifyRes = await this.oauthInstance.authApi.verify({
|
|
2343
|
+
verification_id: verificationInfo.verification_id,
|
|
2344
|
+
verification_code: verificationCode,
|
|
2345
|
+
})
|
|
2341
2346
|
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
provider_id: wxInfo?.appId,
|
|
2346
|
-
provider_code: code,
|
|
2347
|
-
provider_params: {
|
|
2348
|
-
provider_code_type: 'open_id',
|
|
2349
|
-
appid: wxInfo?.appId,
|
|
2350
|
-
},
|
|
2351
|
-
},
|
|
2352
|
-
useWxCloud,
|
|
2353
|
-
)
|
|
2347
|
+
if ((verifyRes as any)?.error_code) {
|
|
2348
|
+
throw verifyRes
|
|
2349
|
+
}
|
|
2354
2350
|
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
}
|
|
2351
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
2352
|
+
const { verification_token } = verifyRes
|
|
2358
2353
|
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
)
|
|
2354
|
+
// 手机登录参数
|
|
2355
|
+
let username = this.formatPhone(rawUsername)
|
|
2356
|
+
let signUpParam: any = { phone_number: username }
|
|
2363
2357
|
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
throw error
|
|
2358
|
+
// 邮箱登录参数
|
|
2359
|
+
if (loginType === 'email') {
|
|
2360
|
+
username = rawUsername
|
|
2361
|
+
signUpParam = { email: username }
|
|
2369
2362
|
}
|
|
2370
|
-
await this.oauthInstance.oauth2client.setCredentials(credentials as Credentials)
|
|
2371
|
-
}
|
|
2372
2363
|
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
resolve(true)
|
|
2380
|
-
} catch (error) {
|
|
2381
|
-
reject(error)
|
|
2382
|
-
}
|
|
2383
|
-
},
|
|
2384
|
-
fail: (res: any) => {
|
|
2385
|
-
const error = new Error(res?.errMsg)
|
|
2386
|
-
;(error as any).code = res?.errno
|
|
2387
|
-
reject(error)
|
|
2388
|
-
},
|
|
2364
|
+
// 2. 根据是否已经是用户,分别走登录或注册逻辑
|
|
2365
|
+
if (verificationInfo.is_user) {
|
|
2366
|
+
// 私有化环境或者自定义应用走v1版本的老逻辑
|
|
2367
|
+
const signInRes = await this.oauthInstance.authApi.signIn({
|
|
2368
|
+
username,
|
|
2369
|
+
verification_token,
|
|
2389
2370
|
})
|
|
2390
|
-
})
|
|
2391
2371
|
|
|
2392
|
-
|
|
2372
|
+
if ((signInRes as any)?.error_code) {
|
|
2373
|
+
throw signInRes
|
|
2374
|
+
}
|
|
2393
2375
|
|
|
2394
|
-
|
|
2376
|
+
if (bindInfo) {
|
|
2377
|
+
const bindRes = await this.oauthInstance.authApi.bindWithProvider({
|
|
2378
|
+
provider_token: (bindInfo as any)?.providerToken,
|
|
2379
|
+
})
|
|
2395
2380
|
|
|
2396
|
-
|
|
2397
|
-
|
|
2381
|
+
if ((bindRes as any)?.error_code) {
|
|
2382
|
+
throw bindRes
|
|
2383
|
+
}
|
|
2384
|
+
}
|
|
2385
|
+
} else {
|
|
2386
|
+
// 自定义应用走signUp逻辑
|
|
2387
|
+
const signUpRes = await this.oauthInstance.authApi.signUp({
|
|
2388
|
+
...signUpParam,
|
|
2389
|
+
verification_token,
|
|
2390
|
+
provider_token: (bindInfo as any)?.providerId,
|
|
2391
|
+
})
|
|
2392
|
+
|
|
2393
|
+
if ((signUpRes as any)?.error_code) {
|
|
2394
|
+
throw signUpRes
|
|
2395
|
+
}
|
|
2396
|
+
}
|
|
2397
|
+
|
|
2398
|
+
return this.createLoginState()
|
|
2398
2399
|
} catch (error) {
|
|
2399
|
-
|
|
2400
|
+
throw error
|
|
2400
2401
|
}
|
|
2401
2402
|
}
|
|
2402
2403
|
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
}
|
|
2412
|
-
const wxInfo = wx.getAccountInfoSync().miniProgram
|
|
2413
|
-
const providerInfo = {
|
|
2414
|
-
provider_params: { provider_code_type: 'phone' },
|
|
2415
|
-
provider_id: wxInfo.appId,
|
|
2416
|
-
}
|
|
2404
|
+
async createLoginState(
|
|
2405
|
+
params?: { version?: string; query?: any },
|
|
2406
|
+
options?: { asyncRefreshUser?: boolean; userInfo?: any },
|
|
2407
|
+
): Promise<LoginState> {
|
|
2408
|
+
const loginState = new LoginState({
|
|
2409
|
+
envId: this.config.env,
|
|
2410
|
+
cache: this.cache,
|
|
2411
|
+
oauthInstance: this.oauthInstance,
|
|
2412
|
+
})
|
|
2417
2413
|
|
|
2418
|
-
|
|
2419
|
-
;(providerInfo as any).provider_code = code
|
|
2414
|
+
await loginState.checkLocalStateAsync()
|
|
2420
2415
|
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2416
|
+
if (options?.userInfo) {
|
|
2417
|
+
loginState.user.setLocalUserInfo(options.userInfo)
|
|
2418
|
+
} else {
|
|
2419
|
+
if (options?.asyncRefreshUser) {
|
|
2420
|
+
loginState.user.refresh(params)
|
|
2421
|
+
} else {
|
|
2422
|
+
await loginState.user.refresh(params)
|
|
2425
2423
|
}
|
|
2424
|
+
}
|
|
2426
2425
|
|
|
2427
|
-
|
|
2428
|
-
provider_token: providerToken.provider_token,
|
|
2429
|
-
provider_id: wxInfo.appId,
|
|
2430
|
-
provider_params: {
|
|
2431
|
-
code: phoneCode,
|
|
2432
|
-
provider_code_type: 'phone',
|
|
2433
|
-
},
|
|
2434
|
-
})
|
|
2435
|
-
if (providerToken.error_code) {
|
|
2436
|
-
throw providerToken
|
|
2437
|
-
}
|
|
2426
|
+
this.config.eventBus?.fire(EVENTS.LOGIN_STATE_CHANGED, { eventType: LOGIN_STATE_CHANGED_TYPE.SIGN_IN })
|
|
2438
2427
|
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2428
|
+
this.config.eventBus?.fire(EVENTS.AUTH_STATE_CHANGED, { event: AUTH_STATE_CHANGED_TYPE.SIGNED_IN })
|
|
2429
|
+
return loginState
|
|
2430
|
+
}
|
|
2442
2431
|
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2432
|
+
async setAccessKey() {
|
|
2433
|
+
let accessToken = ''
|
|
2434
|
+
let scope = ''
|
|
2435
|
+
if (this.config.accessKey) {
|
|
2436
|
+
accessToken = this.config.accessKey
|
|
2437
|
+
scope = 'accessKey'
|
|
2438
|
+
} else if (this.config.auth?.secretId && this.config.auth?.secretKey) {
|
|
2439
|
+
accessToken = ''
|
|
2440
|
+
scope = DEFAULT_NODE_ACCESS_SCOPE
|
|
2448
2441
|
}
|
|
2449
2442
|
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2443
|
+
if (!scope) {
|
|
2444
|
+
return
|
|
2445
|
+
}
|
|
2453
2446
|
|
|
2454
|
-
|
|
2455
|
-
|
|
2447
|
+
try {
|
|
2448
|
+
this.oauthInstance.oauth2client.setAccessKeyCredentials({
|
|
2449
|
+
access_token: accessToken,
|
|
2450
|
+
token_type: 'Bearer',
|
|
2451
|
+
scope,
|
|
2452
|
+
expires_at: new Date(+new Date() + +new Date()),
|
|
2453
|
+
expires_in: +new Date() + +new Date(),
|
|
2454
|
+
})
|
|
2455
|
+
} catch (error) {
|
|
2456
|
+
console.warn('accessKey error: ', error)
|
|
2457
|
+
}
|
|
2456
2458
|
}
|
|
2457
2459
|
|
|
2458
|
-
|
|
2460
|
+
protected formatPhone(phone: string) {
|
|
2459
2461
|
if (!/\s+/.test(phone) && /^\+\d{1,3}\d+/.test(phone)) {
|
|
2460
2462
|
return phone.replace(/^(\+\d{1,2})(\d+)$/, '$1 $2')
|
|
2461
2463
|
}
|
|
@@ -2580,7 +2582,10 @@ class Auth {
|
|
|
2580
2582
|
}
|
|
2581
2583
|
}
|
|
2582
2584
|
|
|
2583
|
-
type TInitAuthOptions = Pick<
|
|
2585
|
+
type TInitAuthOptions = Pick<
|
|
2586
|
+
ICloudbaseAuthConfig,
|
|
2587
|
+
'region' | 'persistence' | 'i18n' | 'accessKey' | 'useWxCloud' | 'auth'
|
|
2588
|
+
> &
|
|
2584
2589
|
Partial<AuthOptions> & {
|
|
2585
2590
|
detectSessionInUrl?: boolean
|
|
2586
2591
|
}
|
|
@@ -2633,6 +2638,7 @@ export function generateAuthInstance(
|
|
|
2633
2638
|
headers: { 'X-SDK-Version': `@cloudbase/js-sdk/${config.sdkVersion}`, ...(config.headers || {}) },
|
|
2634
2639
|
detectSessionInUrl: config.detectSessionInUrl,
|
|
2635
2640
|
debug,
|
|
2641
|
+
auth: options.app?.config?.auth,
|
|
2636
2642
|
}),)
|
|
2637
2643
|
|
|
2638
2644
|
const authInstance = new Auth({
|
|
@@ -2649,6 +2655,7 @@ export function generateAuthInstance(
|
|
|
2649
2655
|
runtime: runtime || 'web',
|
|
2650
2656
|
_fromApp: cloudbase,
|
|
2651
2657
|
oauthInstance,
|
|
2658
|
+
auth: options.app?.config?.auth,
|
|
2652
2659
|
})
|
|
2653
2660
|
|
|
2654
2661
|
// Initialize session with user info callback
|
|
@@ -2680,6 +2687,51 @@ export function generateAuthInstance(
|
|
|
2680
2687
|
|
|
2681
2688
|
const NAMESPACE = 'auth'
|
|
2682
2689
|
|
|
2690
|
+
/**
|
|
2691
|
+
* 计算两个字符串之间的编辑距离(Levenshtein distance)
|
|
2692
|
+
* 用于在用户调用不存在的 Auth 方法时,推荐最相似的方法名
|
|
2693
|
+
*/
|
|
2694
|
+
function levenshteinDistance(a: string, b: string): number {
|
|
2695
|
+
const matrix: number[][] = []
|
|
2696
|
+
for (let i = 0; i <= a.length; i++) {
|
|
2697
|
+
matrix[i] = [i]
|
|
2698
|
+
}
|
|
2699
|
+
for (let j = 0; j <= b.length; j++) {
|
|
2700
|
+
matrix[0][j] = j
|
|
2701
|
+
}
|
|
2702
|
+
for (let i = 1; i <= a.length; i++) {
|
|
2703
|
+
for (let j = 1; j <= b.length; j++) {
|
|
2704
|
+
const cost = a[i - 1].toLowerCase() === b[j - 1].toLowerCase() ? 0 : 1
|
|
2705
|
+
matrix[i][j] = Math.min(
|
|
2706
|
+
matrix[i - 1][j] + 1,
|
|
2707
|
+
matrix[i][j - 1] + 1,
|
|
2708
|
+
matrix[i - 1][j - 1] + cost,
|
|
2709
|
+
)
|
|
2710
|
+
}
|
|
2711
|
+
}
|
|
2712
|
+
return matrix[a.length][b.length]
|
|
2713
|
+
}
|
|
2714
|
+
|
|
2715
|
+
/**
|
|
2716
|
+
* 在方法列表中查找与目标名称最相似的方法
|
|
2717
|
+
* @returns 最相似的方法名,如果没有足够相似的则返回 null
|
|
2718
|
+
*/
|
|
2719
|
+
function findSimilarMethod(target: string, methods: string[]): string | null {
|
|
2720
|
+
let bestMatch: string | null = null
|
|
2721
|
+
let bestDistance = Infinity
|
|
2722
|
+
|
|
2723
|
+
for (const method of methods) {
|
|
2724
|
+
// 跳过私有方法和构造函数
|
|
2725
|
+
if (method.startsWith('_') || method === 'constructor') continue
|
|
2726
|
+
const distance = levenshteinDistance(target, method)
|
|
2727
|
+
if (distance < bestDistance) {
|
|
2728
|
+
bestDistance = distance
|
|
2729
|
+
bestMatch = method
|
|
2730
|
+
}
|
|
2731
|
+
}
|
|
2732
|
+
return bestMatch
|
|
2733
|
+
}
|
|
2734
|
+
|
|
2683
2735
|
const component: ICloudbaseComponent = {
|
|
2684
2736
|
name: COMPONENT_NAME,
|
|
2685
2737
|
namespace: NAMESPACE,
|
|
@@ -2735,8 +2787,30 @@ const component: ICloudbaseComponent = {
|
|
|
2735
2787
|
const authProto = auth.call(this, config)
|
|
2736
2788
|
Object.assign(auth, authProto)
|
|
2737
2789
|
Object.setPrototypeOf(auth, Object.getPrototypeOf(authProto))
|
|
2738
|
-
|
|
2739
|
-
|
|
2790
|
+
|
|
2791
|
+
// 包装 Proxy,当用户调用不存在的方法时提供 "Did you mean?" 提示
|
|
2792
|
+
const authWithHint = typeof Proxy !== 'undefined'
|
|
2793
|
+
? new Proxy(auth, {
|
|
2794
|
+
get(target, prop, receiver) {
|
|
2795
|
+
const value = Reflect.get(target, prop, receiver)
|
|
2796
|
+
if (value !== undefined || typeof prop !== 'string') {
|
|
2797
|
+
return value
|
|
2798
|
+
}
|
|
2799
|
+
// 查找最相似的方法名
|
|
2800
|
+
const allKeys = Object.getOwnPropertyNames(Object.getPrototypeOf(target))
|
|
2801
|
+
.concat(Object.keys(target))
|
|
2802
|
+
.filter(k => typeof target[k] === 'function')
|
|
2803
|
+
const suggestion = findSimilarMethod(prop, allKeys)
|
|
2804
|
+
if (suggestion) {
|
|
2805
|
+
console.warn(`[CloudBase Auth] auth.${prop} is not a function. Did you mean: auth.${suggestion}() ?`)
|
|
2806
|
+
}
|
|
2807
|
+
return value
|
|
2808
|
+
},
|
|
2809
|
+
})
|
|
2810
|
+
: auth
|
|
2811
|
+
|
|
2812
|
+
this[NAMESPACE] = authWithHint
|
|
2813
|
+
return authWithHint
|
|
2740
2814
|
},
|
|
2741
2815
|
}
|
|
2742
2816
|
|
|
@@ -2746,7 +2820,7 @@ try {
|
|
|
2746
2820
|
cloudbase.registerComponent(component)
|
|
2747
2821
|
} catch (e) {}
|
|
2748
2822
|
|
|
2749
|
-
export { UserInfo, Auth }
|
|
2823
|
+
export { UserInfo, Auth, WeixinAuthProvider, CustomAuthProvider, AnonymousAuthProvider }
|
|
2750
2824
|
/**
|
|
2751
2825
|
* @api 手动注册至cloudbase app
|
|
2752
2826
|
*/
|