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