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