@cloudbase/auth 2.23.3 → 2.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/index.ts CHANGED
@@ -5,7 +5,14 @@ import type { ICloudbaseAuthConfig, IUser, IUserInfo, ILoginState } from '@cloud
5
5
  import type { ICloudbaseComponent } from '@cloudbase/types/component'
6
6
  import type { GrantProviderTokenResponse, ProviderSubType } from '@cloudbase/oauth/dist/cjs/auth/models'
7
7
  import type { authModels, AuthOptions, Credentials } from '@cloudbase/oauth'
8
- import { CloudbaseOAuth, AUTH_API_PREFIX } from '@cloudbase/oauth'
8
+ import {
9
+ CloudbaseOAuth,
10
+ AUTH_API_PREFIX,
11
+ LOGIN_STATE_CHANGED_TYPE,
12
+ EVENTS,
13
+ AUTH_STATE_CHANGED_TYPE,
14
+ OAUTH_TYPE,
15
+ } from '@cloudbase/oauth'
9
16
  import { useAuthAdapter } from './adapter'
10
17
  import {
11
18
  printWarn,
@@ -18,23 +25,13 @@ import {
18
25
  adapterForWxMp,
19
26
  useDefaultAdapter,
20
27
  } from './utilities'
28
+ import { SbaseApi } from './sbaseApi'
21
29
 
22
30
  declare const cloudbase: ICloudbase
23
31
  declare const wx: any
24
32
 
25
33
  const COMPONENT_NAME = 'auth'
26
34
 
27
- const LOGIN_STATE_CHANGED_TYPE = {
28
- SIGN_OUT: 'sign_out',
29
- SIGN_IN: 'sign_in',
30
- CREDENTIALS_ERROR: 'credentials_error',
31
- }
32
-
33
- const EVENTS = {
34
- // 登录态改变后触发
35
- LOGIN_STATE_CHANGED: 'loginStateChanged',
36
- }
37
-
38
35
  interface UserInfo {
39
36
  uid?: string
40
37
  gender?: string
@@ -51,7 +48,7 @@ interface UserInfo {
51
48
  created_from?: string
52
49
  }
53
50
 
54
- const eventBus = new CloudbaseEventEmitter()
51
+ export const eventBus = new CloudbaseEventEmitter()
55
52
 
56
53
  const onCredentialsError = (params) => {
57
54
  eventBus.fire(EVENTS.LOGIN_STATE_CHANGED, { ...params, eventType: LOGIN_STATE_CHANGED_TYPE.CREDENTIALS_ERROR })
@@ -62,14 +59,14 @@ interface IUserOptions {
62
59
  oauthInstance: CloudbaseOAuth
63
60
  }
64
61
 
65
- class User implements IUser {
62
+ export class User implements IUser {
66
63
  public uid?: string
67
64
  public gender?: string
68
65
  public picture?: string
69
66
  public email?: string
70
67
  public emailVerified?: boolean
71
68
  public phoneNumber?: string
72
- public username?: string
69
+ public username?: string // 用户名称,长度 5-24 位,支持字符中英文、数字、特殊字符(仅支持_-),不支持中文
73
70
  public name?: string
74
71
  public providers?: {
75
72
  id?: string
@@ -221,12 +218,21 @@ class User implements IUser {
221
218
  return newUserInfo
222
219
  }
223
220
 
224
- private getLocalUserInfo(key: string): string | boolean {
221
+ public getLocalUserInfo(key?: string): string | boolean | Record<string, any> {
225
222
  const { userInfoKey } = this.cache.keys
226
223
  const userInfo = this.cache.getStore(userInfoKey)
224
+
225
+ if (!key) return userInfo || {}
226
+
227
227
  return userInfo[key]
228
228
  }
229
229
 
230
+ public setLocalUserInfo(userInfo: any) {
231
+ const { userInfoKey } = this.cache.keys
232
+ this.cache.setStore(userInfoKey, userInfo)
233
+ this.setUserInfo()
234
+ }
235
+
230
236
  private async getLocalUserInfoAsync(key: string): Promise<string> {
231
237
  const { userInfoKey } = this.cache.keys
232
238
  const userInfo = await this.cache.getStoreAsync(userInfoKey)
@@ -251,16 +257,11 @@ class User implements IUser {
251
257
  'created_from',
252
258
  'providers',
253
259
  'username',
260
+ 'created_at',
254
261
  ].forEach((infoKey) => {
255
262
  this[infoKey] = userInfo[infoKey]
256
263
  })
257
264
  }
258
-
259
- private setLocalUserInfo(userInfo: any) {
260
- const { userInfoKey } = this.cache.keys
261
- this.cache.setStore(userInfoKey, userInfo)
262
- this.setUserInfo()
263
- }
264
265
  }
265
266
  interface ILoginStateOptions extends IUserOptions {
266
267
  envId: string
@@ -297,16 +298,13 @@ export class LoginState implements ILoginState {
297
298
  }
298
299
  }
299
300
 
300
- class Auth {
301
- private readonly config: ICloudbaseAuthConfig
302
- private readonly cache: ICloudbaseCache
303
-
304
- private oauthInstance: CloudbaseOAuth
305
-
306
- constructor(config: ICloudbaseAuthConfig & { cache: ICloudbaseCache; request?: ICloudbaseRequest; runtime?: string },) {
307
- this.config = config
308
- this.cache = config.cache
309
- this.oauthInstance = config.oauthInstance
301
+ class Auth extends SbaseApi {
302
+ constructor(config: ICloudbaseAuthConfig & {
303
+ cache: ICloudbaseCache
304
+ request?: ICloudbaseRequest
305
+ runtime?: string
306
+ },) {
307
+ super(config)
310
308
  this.setAccessKey()
311
309
  }
312
310
 
@@ -437,35 +435,36 @@ class Auth {
437
435
  `如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
438
436
  ],
439
437
  })
440
- public async getCurrentUser() {
438
+ public async getCurrentUser(): Promise<(authModels.UserInfo & Partial<User>) | null> {
441
439
  const loginState = await this.getLoginState()
442
440
  if (loginState) {
441
+ const userInfo = loginState.user.getLocalUserInfo() as authModels.UserInfo
443
442
  await loginState.user.checkLocalInfoAsync()
444
- return loginState.user || null
443
+ return { ...loginState.user, ...userInfo }
445
444
  }
446
445
  return null
447
446
  }
448
447
 
449
- /**
450
- * 匿名登录
451
- * @returns {Promise<LoginState>}
452
- * @memberof Auth
453
- */
454
- @catchErrorsDecorator({
455
- title: '匿名登录失败',
456
- messages: [
457
- '请确认以下各项:',
458
- ' 1 - 当前环境是否开启了匿名登录',
459
- ' 2 - 调用 auth().signInAnonymously() 的语法或参数是否正确',
460
- `如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
461
- ],
462
- })
463
- public async signInAnonymously(data: {
464
- provider_token?: string
465
- } = {},): Promise<LoginState> {
466
- await this.oauthInstance.authApi.signInAnonymously(data)
467
- return this.createLoginState()
468
- }
448
+ // /**
449
+ // * 匿名登录
450
+ // * @returns {Promise<LoginState>}
451
+ // * @memberof Auth
452
+ // */
453
+ // @catchErrorsDecorator({
454
+ // title: '匿名登录失败',
455
+ // messages: [
456
+ // '请确认以下各项:',
457
+ // ' 1 - 当前环境是否开启了匿名登录',
458
+ // ' 2 - 调用 auth().signInAnonymously() 的语法或参数是否正确',
459
+ // `如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
460
+ // ],
461
+ // })
462
+ // public async signInAnonymously(data: {
463
+ // provider_token?: string
464
+ // } = {},): Promise<LoginState> {
465
+ // await this.oauthInstance.authApi.signInAnonymously(data)
466
+ // return this.createLoginState()
467
+ // }
469
468
 
470
469
  /**
471
470
  * 匿名登录
@@ -615,76 +614,76 @@ class Auth {
615
614
  * @returns {Promise<LoginState>}
616
615
  * @memberof Auth
617
616
  */
618
- @catchErrorsDecorator({
619
- title: '小程序openId静默登录失败',
620
- messages: [
621
- '请确认以下各项:',
622
- ' 1 - 当前环境是否开启了小程序openId静默登录',
623
- ' 2 - 调用 auth().signInWithOpenId() 的语法或参数是否正确',
624
- `如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
625
- ],
626
- })
627
- public async signInWithOpenId({ useWxCloud = true } = {}): Promise<LoginState> {
628
- if (!adapterForWxMp.isMatch()) {
629
- throw Error('wx api undefined')
630
- }
631
- const wxInfo = wx.getAccountInfoSync().miniProgram
632
-
633
- const mainFunc = async (code) => {
634
- let result: GrantProviderTokenResponse | undefined = undefined
635
- let credentials: Credentials | undefined = undefined
636
-
637
- try {
638
- result = await this.oauthInstance.authApi.grantProviderToken(
639
- {
640
- provider_id: wxInfo?.appId,
641
- provider_code: code,
642
- provider_params: {
643
- provider_code_type: 'open_id',
644
- appid: wxInfo?.appId,
645
- },
646
- },
647
- useWxCloud,
648
- )
649
-
650
- if ((result as any)?.error_code || !result.provider_token) {
651
- throw result
652
- }
653
-
654
- credentials = await this.oauthInstance.authApi.signInWithProvider(
655
- { provider_token: result.provider_token },
656
- useWxCloud,
657
- )
658
-
659
- if ((credentials as any)?.error_code) {
660
- throw credentials
661
- }
662
- } catch (error) {
663
- throw error
664
- }
665
- await this.oauthInstance.oauth2client.setCredentials(credentials as Credentials)
666
- }
667
-
668
- await new Promise((resolve, reject) => {
669
- wx.login({
670
- success: async (res: { code: string }) => {
671
- try {
672
- await mainFunc(res.code)
673
- resolve(true)
674
- } catch (error) {
675
- reject(error)
676
- }
677
- },
678
- fail: (res: any) => {
679
- const error = new Error(res?.errMsg)
680
- ;(error as any).code = res?.errno
681
- reject(error)
682
- },
683
- })
684
- })
685
-
686
- return this.createLoginState()
687
- }
617
+ // @catchErrorsDecorator({
618
+ // title: '小程序openId静默登录失败',
619
+ // messages: [
620
+ // '请确认以下各项:',
621
+ // ' 1 - 当前环境是否开启了小程序openId静默登录',
622
+ // ' 2 - 调用 auth().signInWithOpenId() 的语法或参数是否正确',
623
+ // `如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
624
+ // ],
625
+ // })
626
+ // public async signInWithOpenId({ useWxCloud = true } = {}): Promise<LoginState> {
627
+ // if (!adapterForWxMp.isMatch()) {
628
+ // throw Error('wx api undefined')
629
+ // }
630
+ // const wxInfo = wx.getAccountInfoSync().miniProgram
631
+
632
+ // const mainFunc = async (code) => {
633
+ // let result: GrantProviderTokenResponse | undefined = undefined
634
+ // let credentials: Credentials | undefined = undefined
635
+
636
+ // try {
637
+ // result = await this.oauthInstance.authApi.grantProviderToken(
638
+ // {
639
+ // provider_id: wxInfo?.appId,
640
+ // provider_code: code,
641
+ // provider_params: {
642
+ // provider_code_type: 'open_id',
643
+ // appid: wxInfo?.appId,
644
+ // },
645
+ // },
646
+ // useWxCloud,
647
+ // )
648
+
649
+ // if ((result as any)?.error_code || !result.provider_token) {
650
+ // throw result
651
+ // }
652
+
653
+ // credentials = await this.oauthInstance.authApi.signInWithProvider(
654
+ // { provider_token: result.provider_token },
655
+ // useWxCloud,
656
+ // )
657
+
658
+ // if ((credentials as any)?.error_code) {
659
+ // throw credentials
660
+ // }
661
+ // } catch (error) {
662
+ // throw error
663
+ // }
664
+ // await this.oauthInstance.oauth2client.setCredentials(credentials as Credentials)
665
+ // }
666
+
667
+ // await new Promise((resolve, reject) => {
668
+ // wx.login({
669
+ // success: async (res: { code: string }) => {
670
+ // try {
671
+ // await mainFunc(res.code)
672
+ // resolve(true)
673
+ // } catch (error) {
674
+ // reject(error)
675
+ // }
676
+ // },
677
+ // fail: (res: any) => {
678
+ // const error = new Error(res?.errMsg)
679
+ // ;(error as any).code = res?.errno
680
+ // reject(error)
681
+ // },
682
+ // })
683
+ // })
684
+
685
+ // return this.createLoginState()
686
+ // }
688
687
 
689
688
  /**
690
689
  * 小程序unionId静默登录
@@ -760,59 +759,59 @@ class Auth {
760
759
  * @returns {Promise<LoginState>}
761
760
  * @memberof Auth
762
761
  */
763
- @catchErrorsDecorator({
764
- title: '小程序手机号授权登录失败',
765
- messages: [
766
- '请确认以下各项:',
767
- ' 1 - 当前环境是否开启了小程序手机号授权登录',
768
- ' 2 - 调用 auth().signInWithPhoneAuth() 的语法或参数是否正确',
769
- `如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
770
- ],
771
- })
772
- public async signInWithPhoneAuth({ phoneCode = '' }): Promise<LoginState> {
773
- if (!adapterForWxMp.isMatch()) {
774
- throw Error('wx api undefined')
775
- }
776
- const wxInfo = wx.getAccountInfoSync().miniProgram
777
- const providerInfo = {
778
- provider_params: { provider_code_type: 'phone' },
779
- provider_id: wxInfo.appId,
780
- }
781
-
782
- const { code } = await wx.login()
783
- ;(providerInfo as any).provider_code = code
784
-
785
- try {
786
- let providerToken = await this.oauthInstance.authApi.grantProviderToken(providerInfo)
787
- if (providerToken.error_code) {
788
- throw providerToken
789
- }
790
-
791
- providerToken = await this.oauthInstance.authApi.patchProviderToken({
792
- provider_token: providerToken.provider_token,
793
- provider_id: wxInfo.appId,
794
- provider_params: {
795
- code: phoneCode,
796
- provider_code_type: 'phone',
797
- },
798
- })
799
- if (providerToken.error_code) {
800
- throw providerToken
801
- }
802
-
803
- const signInRes = await this.oauthInstance.authApi.signInWithProvider({
804
- provider_token: providerToken.provider_token,
805
- })
806
-
807
- if ((signInRes as any)?.error_code) {
808
- throw signInRes
809
- }
810
- } catch (error) {
811
- throw error
812
- }
813
-
814
- return this.createLoginState()
815
- }
762
+ // @catchErrorsDecorator({
763
+ // title: '小程序手机号授权登录失败',
764
+ // messages: [
765
+ // '请确认以下各项:',
766
+ // ' 1 - 当前环境是否开启了小程序手机号授权登录',
767
+ // ' 2 - 调用 auth().signInWithPhoneAuth() 的语法或参数是否正确',
768
+ // `如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
769
+ // ],
770
+ // })
771
+ // public async signInWithPhoneAuth({ phoneCode = '' }): Promise<LoginState> {
772
+ // if (!adapterForWxMp.isMatch()) {
773
+ // throw Error('wx api undefined')
774
+ // }
775
+ // const wxInfo = wx.getAccountInfoSync().miniProgram
776
+ // const providerInfo = {
777
+ // provider_params: { provider_code_type: 'phone' },
778
+ // provider_id: wxInfo.appId,
779
+ // }
780
+
781
+ // const { code } = await wx.login()
782
+ // ;(providerInfo as any).provider_code = code
783
+
784
+ // try {
785
+ // let providerToken = await this.oauthInstance.authApi.grantProviderToken(providerInfo)
786
+ // if (providerToken.error_code) {
787
+ // throw providerToken
788
+ // }
789
+
790
+ // providerToken = await this.oauthInstance.authApi.patchProviderToken({
791
+ // provider_token: providerToken.provider_token,
792
+ // provider_id: wxInfo.appId,
793
+ // provider_params: {
794
+ // code: phoneCode,
795
+ // provider_code_type: 'phone',
796
+ // },
797
+ // })
798
+ // if (providerToken.error_code) {
799
+ // throw providerToken
800
+ // }
801
+
802
+ // const signInRes = await this.oauthInstance.authApi.signInWithProvider({
803
+ // provider_token: providerToken.provider_token,
804
+ // })
805
+
806
+ // if ((signInRes as any)?.error_code) {
807
+ // throw signInRes
808
+ // }
809
+ // } catch (error) {
810
+ // throw error
811
+ // }
812
+
813
+ // return this.createLoginState()
814
+ // }
816
815
 
817
816
  /**
818
817
  * 小程序短信验证码登陆
@@ -894,21 +893,21 @@ class Auth {
894
893
  * @returns {Promise<LoginState>}
895
894
  * @memberof Auth
896
895
  */
897
- @catchErrorsDecorator({
898
- title: '自定义登录失败',
899
- messages: [
900
- '请确认以下各项:',
901
- ' 1 - 当前环境是否开启了自定义登录',
902
- ' 2 - 调用 auth().signInWithCustomTicket() 的语法或参数是否正确',
903
- ' 3 - ticket 是否归属于当前环境',
904
- ' 4 - 创建 ticket 的自定义登录私钥是否过期',
905
- `如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
906
- ],
907
- })
908
- public async signInWithCustomTicket(): Promise<LoginState> {
909
- await this.oauthInstance.authApi.signInWithCustomTicket()
910
- return this.createLoginState()
911
- }
896
+ // @catchErrorsDecorator({
897
+ // title: '自定义登录失败',
898
+ // messages: [
899
+ // '请确认以下各项:',
900
+ // ' 1 - 当前环境是否开启了自定义登录',
901
+ // ' 2 - 调用 auth().signInWithCustomTicket() 的语法或参数是否正确',
902
+ // ' 3 - ticket 是否归属于当前环境',
903
+ // ' 4 - 创建 ticket 的自定义登录私钥是否过期',
904
+ // `如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
905
+ // ],
906
+ // })
907
+ // public async signInWithCustomTicket(): Promise<LoginState> {
908
+ // await this.oauthInstance.authApi.signInWithCustomTicket()
909
+ // return this.createLoginState()
910
+ // }
912
911
 
913
912
  /**
914
913
  *
@@ -921,25 +920,25 @@ class Auth {
921
920
  return this.createLoginState(params)
922
921
  }
923
922
 
924
- /**
925
- *
926
- * @param {authModels.SignUpRequest} params
927
- * @returns {Promise<LoginState>}
928
- * @memberof Auth
929
- */
930
- @catchErrorsDecorator({
931
- title: '注册失败',
932
- messages: [
933
- '请确认以下各项:',
934
- ' 1 - 当前环境是否开启了指定登录方式',
935
- ' 2 - 调用 auth().signUp() 的语法或参数是否正确',
936
- `如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
937
- ],
938
- })
939
- public async signUp(params: authModels.SignUpRequest): Promise<LoginState> {
940
- await this.oauthInstance.authApi.signUp(params)
941
- return this.createLoginState()
942
- }
923
+ // /**
924
+ // *
925
+ // * @param {authModels.SignUpRequest} params
926
+ // * @returns {Promise<LoginState>}
927
+ // * @memberof Auth
928
+ // */
929
+ // @catchErrorsDecorator({
930
+ // title: '注册失败',
931
+ // messages: [
932
+ // '请确认以下各项:',
933
+ // ' 1 - 当前环境是否开启了指定登录方式',
934
+ // ' 2 - 调用 auth().signUp() 的语法或参数是否正确',
935
+ // `如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
936
+ // ],
937
+ // })
938
+ // public async signUp(params: authModels.SignUpRequest): Promise<any> {
939
+ // await this.oauthInstance.authApi.signUp(params)
940
+ // return this.createLoginState()
941
+ // }
943
942
 
944
943
  /**
945
944
  * 设置密码
@@ -975,22 +974,25 @@ class Auth {
975
974
  /**
976
975
  * 登出
977
976
  */
978
- @catchErrorsDecorator({
979
- title: '用户登出失败',
980
- messages: [
981
- '请确认以下各项:',
982
- ' 1 - 调用 auth().signOut() 的语法或参数是否正确',
983
- ' 2 - 当前用户是否为匿名登录(匿名登录不支持signOut)',
984
- `如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
985
- ],
986
- })
987
- public async signOut(params?: authModels.SignoutRequest): Promise<void | authModels.SignoutReponse> {
988
- const { userInfoKey } = this.cache.keys
989
- const res = await this.oauthInstance.authApi.signOut(params)
990
- await this.cache.removeStoreAsync(userInfoKey)
991
- eventBus.fire(EVENTS.LOGIN_STATE_CHANGED, { eventType: LOGIN_STATE_CHANGED_TYPE.SIGN_OUT })
992
- return res
993
- }
977
+ // @catchErrorsDecorator({
978
+ // title: '用户登出失败',
979
+ // messages: [
980
+ // '请确认以下各项:',
981
+ // ' 1 - 调用 auth().signOut() 的语法或参数是否正确',
982
+ // ' 2 - 当前用户是否为匿名登录(匿名登录不支持signOut)',
983
+ // `如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
984
+ // ],
985
+ // })
986
+ // public async signOut(params?: authModels.SignoutRequest): Promise<void | authModels.SignoutReponse> {
987
+ // const { userInfoKey } = this.cache.keys
988
+ // const res = await this.oauthInstance.authApi.signOut(params)
989
+ // await this.cache.removeStoreAsync(userInfoKey)
990
+
991
+ // eventBus.fire(EVENTS.LOGIN_STATE_CHANGED, { eventType: LOGIN_STATE_CHANGED_TYPE.SIGN_OUT })
992
+
993
+ // eventBus.fire(EVENTS.AUTH_STATE_CHANGED, { event: AUTH_STATE_CHANGED_TYPE.SIGNED_OUT })
994
+ // return res
995
+ // }
994
996
 
995
997
  /**
996
998
  * 获取本地登录态-同步
@@ -1059,8 +1061,8 @@ class Auth {
1059
1061
  `如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
1060
1062
  ],
1061
1063
  })
1062
- public async getUserInfo(params?: { version?: string }): Promise<IUserInfo> {
1063
- return this.oauthInstance.authApi.getUserInfo(params)
1064
+ public async getUserInfo(): Promise<(authModels.UserInfo & Partial<User>) | null> {
1065
+ return this.getCurrentUser()
1064
1066
  }
1065
1067
 
1066
1068
  @catchErrorsDecorator({
@@ -1188,7 +1190,7 @@ class Auth {
1188
1190
  public async onLoginStateChanged(callback: Function) {
1189
1191
  eventBus.on(EVENTS.LOGIN_STATE_CHANGED, async (params) => {
1190
1192
  // getLoginState会重复触发getCredentials,导致死循环,所以getCredentials出错不再出发getLoginState
1191
- const loginState = params?.data?.eventType !== LOGIN_STATE_CHANGED_TYPE.CREDENTIALS_ERROR ? await this.getLoginState() : {}
1193
+ const loginState = params?.data?.eventType !== LOGIN_STATE_CHANGED_TYPE.CREDENTIALS_ERROR ? await this.getLoginState() : {}
1192
1194
  callback.call(this, { ...params, ...loginState })
1193
1195
  })
1194
1196
  // 立刻执行一次回调
@@ -1259,53 +1261,10 @@ class Auth {
1259
1261
  return this.oauthInstance.authApi.getUserBehaviorLog(params)
1260
1262
  }
1261
1263
 
1262
- /**
1263
- * 跳转系统默认登录页
1264
- * @returns {Promise<authModels.ToDefaultLoginPage>}
1265
- * @memberof Auth
1266
- */
1267
- public async toDefaultLoginPage(params: authModels.ToDefaultLoginPage = {}): Promise<void> {
1268
- const configVersion = params.config_version || 'env'
1269
- const query = Object.keys(params.query || {})
1270
- .map(key => `${key}=${params.query[key]}`)
1271
- .join('&')
1272
-
1273
- if (adapterForWxMp.isMatch()) {
1274
- wx.navigateTo({ url: `/packages/$wd_system/pages/login/index${query ? `?${query}` : ''}` })
1275
- } else {
1276
- const redirectUri = params.redirect_uri || window.location.href
1277
- const urlObj = new URL(redirectUri)
1278
- const loginPage = `${urlObj.origin}/__auth/?app_id=${params.app_id || ''}&env_id=${this.config.env}&client_id=${
1279
- this.config.clientId || this.config.env
1280
- }&config_version=${configVersion}&redirect_uri=${encodeURIComponent(redirectUri)}${query ? `&${query}` : ''}`
1281
- window.location.href = loginPage
1282
- }
1283
- }
1284
-
1285
- private async createLoginState(
1286
- params?: { version?: string; query?: any },
1287
- options?: { asyncRefreshUser?: boolean },
1288
- ): Promise<LoginState> {
1289
- const loginState = new LoginState({
1290
- envId: this.config.env,
1291
- cache: this.cache,
1292
- oauthInstance: this.oauthInstance,
1293
- })
1294
-
1295
- await loginState.checkLocalStateAsync()
1296
- if (options?.asyncRefreshUser) {
1297
- loginState.user.refresh(params)
1298
- } else {
1299
- await loginState.user.refresh(params)
1300
- }
1301
- eventBus.fire(EVENTS.LOGIN_STATE_CHANGED, { eventType: LOGIN_STATE_CHANGED_TYPE.SIGN_IN })
1302
- return loginState
1303
- }
1304
-
1305
1264
  /**
1306
1265
  * sms/email 验证码登录/注册,逻辑一致收敛
1307
1266
  */
1308
- private async signInWithUsername({
1267
+ public async signInWithUsername({
1309
1268
  verificationInfo = { verification_id: '', is_user: false },
1310
1269
  verificationCode = '',
1311
1270
  username: rawUsername = '',
@@ -1327,7 +1286,7 @@ class Auth {
1327
1286
  const { verification_token } = verifyRes
1328
1287
 
1329
1288
  // 手机登录参数
1330
- let username = /^\+\d{1,3}\s+\d+/.test(rawUsername) ? rawUsername : `+86 ${rawUsername}`
1289
+ let username = /^\+\d{1,3}\s+/.test(rawUsername) ? rawUsername : `+86 ${rawUsername}`
1331
1290
  let signUpParam: any = { phone_number: username }
1332
1291
 
1333
1292
  // 邮箱登录参数
@@ -1376,7 +1335,35 @@ class Auth {
1376
1335
  }
1377
1336
  }
1378
1337
 
1379
- private async setAccessKey() {
1338
+ async createLoginState(
1339
+ params?: { version?: string; query?: any },
1340
+ options?: { asyncRefreshUser?: boolean; userInfo?: any },
1341
+ ): Promise<LoginState> {
1342
+ const loginState = new LoginState({
1343
+ envId: this.config.env,
1344
+ cache: this.cache,
1345
+ oauthInstance: this.oauthInstance,
1346
+ })
1347
+
1348
+ await loginState.checkLocalStateAsync()
1349
+
1350
+ if (options?.userInfo) {
1351
+ loginState.user.setLocalUserInfo(options.userInfo)
1352
+ } else {
1353
+ if (options?.asyncRefreshUser) {
1354
+ loginState.user.refresh(params)
1355
+ } else {
1356
+ await loginState.user.refresh(params)
1357
+ }
1358
+ }
1359
+
1360
+ eventBus.fire(EVENTS.LOGIN_STATE_CHANGED, { eventType: LOGIN_STATE_CHANGED_TYPE.SIGN_IN })
1361
+
1362
+ eventBus.fire(EVENTS.AUTH_STATE_CHANGED, { event: AUTH_STATE_CHANGED_TYPE.SIGNED_IN })
1363
+ return loginState
1364
+ }
1365
+
1366
+ async setAccessKey() {
1380
1367
  if (this.config.accessKey) {
1381
1368
  try {
1382
1369
  this.oauthInstance.oauth2client.setAccessKeyCredentials({
@@ -1393,7 +1380,10 @@ class Auth {
1393
1380
  }
1394
1381
  }
1395
1382
 
1396
- type TInitAuthOptions = Pick<ICloudbaseAuthConfig, 'region' | 'persistence' | 'i18n' | 'accessKey' | 'useWxCloud'> & Partial<AuthOptions>
1383
+ type TInitAuthOptions = Pick<ICloudbaseAuthConfig, 'region' | 'persistence' | 'i18n' | 'accessKey' | 'useWxCloud'> &
1384
+ Partial<AuthOptions> & {
1385
+ detectSessionInUrl?: boolean
1386
+ }
1397
1387
 
1398
1388
  export function generateAuthInstance(
1399
1389
  config: TInitAuthOptions,
@@ -1405,10 +1395,11 @@ export function generateAuthInstance(
1405
1395
  platform?: ICloudbase['platform']
1406
1396
  app?: ICloudbase
1407
1397
  debug?: ICloudbaseAuthConfig['debug']
1398
+ detectSessionInUrl?: ICloudbaseAuthConfig['detectSessionInUrl']
1408
1399
  },
1409
1400
  ) {
1410
1401
  const { region = 'ap-shanghai', i18n, accessKey, useWxCloud } = config
1411
- const platform = options?.platform || (useDefaultAdapter() as ICloudbasePlatformInfo)
1402
+ const platform = options?.platform || (useDefaultAdapter.bind(options)() as ICloudbasePlatformInfo)
1412
1403
  const { runtime, adapter } = platform
1413
1404
 
1414
1405
  const { env, clientId, debug, cache, app: cloudbase } = options || {}
@@ -1423,6 +1414,7 @@ export function generateAuthInstance(
1423
1414
  i18n,
1424
1415
  accessKey,
1425
1416
  useWxCloud,
1417
+ eventBus,
1426
1418
  }
1427
1419
 
1428
1420
  const oauthInstance = new CloudbaseOAuth(useAuthAdapter({
@@ -1439,6 +1431,8 @@ export function generateAuthInstance(
1439
1431
  adapter,
1440
1432
  onCredentialsError,
1441
1433
  headers: { 'X-SDK-Version': `@cloudbase/js-sdk/${config.sdkVersion}`, ...(config.headers || {}) },
1434
+ detectSessionInUrl: config.detectSessionInUrl,
1435
+ debug,
1442
1436
  }),)
1443
1437
 
1444
1438
  const authInstance = new Auth({
@@ -1458,21 +1452,47 @@ export function generateAuthInstance(
1458
1452
  oauthInstance,
1459
1453
  })
1460
1454
 
1455
+ // Initialize session with user info callback
1456
+ // This handles OAuth callback URL detection and creates login state atomically
1457
+ oauthInstance.initializeSession(async (data, error) => {
1458
+ if (!data) return
1459
+
1460
+ if (data.type === OAUTH_TYPE.SIGN_IN) {
1461
+ if (error) {
1462
+ eventBus.fire(EVENTS.AUTH_STATE_CHANGED, {
1463
+ event: AUTH_STATE_CHANGED_TYPE.SIGNED_IN,
1464
+ info: { ...data, error },
1465
+ })
1466
+ } else if (data.user) {
1467
+ // 使用已获取的 user 信息创建 LoginState,复用 createLoginState 逻辑
1468
+ // 但跳过 refresh() 避免再次请求 API 导致死锁
1469
+ authInstance.createLoginState({}, { userInfo: data.user })
1470
+ }
1471
+ } else if (data.type === OAUTH_TYPE.BIND_IDENTITY) {
1472
+ eventBus.fire(EVENTS.AUTH_STATE_CHANGED, {
1473
+ event: AUTH_STATE_CHANGED_TYPE.BIND_IDENTITY,
1474
+ info: { ...data, error },
1475
+ })
1476
+ }
1477
+ })
1478
+
1461
1479
  return { authInstance, oauthInstance }
1462
1480
  }
1463
1481
 
1464
1482
  const component: ICloudbaseComponent = {
1465
1483
  name: COMPONENT_NAME,
1466
1484
  namespace: 'auth',
1467
- entity(config: TInitAuthOptions = {
1468
- region: '',
1469
- persistence: 'local',
1470
- apiPath: AUTH_API_PREFIX,
1471
- },) {
1472
- if (this.authInstance) {
1473
- printWarn(ERRORS.INVALID_OPERATION, 'every cloudbase instance should has only one auth object')
1485
+ entity(config?: TInitAuthOptions) {
1486
+ if (this.authInstance && !config) {
1487
+ // printWarn(ERRORS.INVALID_OPERATION, 'every cloudbase instance should has only one auth object')
1474
1488
  return this.authInstance
1475
1489
  }
1490
+
1491
+ config = config || {
1492
+ region: '',
1493
+ persistence: 'local',
1494
+ apiPath: AUTH_API_PREFIX,
1495
+ }
1476
1496
  const { adapter } = this.platform
1477
1497
  // 如不明确指定persistence则优先取各平台adapter首选,其次localStorage
1478
1498
  const newPersistence = config.persistence || adapter.primaryStorage
@@ -1490,6 +1510,7 @@ const component: ICloudbaseComponent = {
1490
1510
  accessKey: this.config.accessKey,
1491
1511
  useWxCloud: this.config.useWxCloud,
1492
1512
  sdkVersion: this.version,
1513
+ detectSessionInUrl: this.config.auth?.detectSessionInUrl,
1493
1514
  },
1494
1515
  {
1495
1516
  env: this.config.env,