使用共享用户访问组时,Firebase Auth 用户已过时

Posted

技术标签:

【中文标题】使用共享用户访问组时,Firebase Auth 用户已过时【英文标题】:Firebase Auth user is outdated when using shared user access group 【发布时间】:2021-03-10 05:16:30 【问题描述】:

在应用与其小部件扩展之间共享身份验证状态,但有时身份验证状态不同步。当用户从我的应用程序登录/注销时,它会刷新小部件时间线,然后检查身份验证状态以显示正确的项目。但是,如果我将用户注销,有时对 Auth.auth().currentUser 的调用仍会返回有效用户。

我已确认这两个应用都在同一个用户访问组中,并且我已在每个目标的功能中启用了该应用组。一组更新身份验证状态与另一组可以访问该状态之间是否存在延迟?

小部件代码

    struct Provider: TimelineProvider 
        ...
        func getTimeline(in context: Context, completion: @escaping (Timeline<BirthdaysEntry>) -> Void) 
            if let uid = Auth.auth().currentUser?.uid 
                // fetch data from firestore
             else 
                // logged out 
            
        
        ...
    

    @main
    struct MyWidget: Widget 
        private let kind = "my_widget"
        
        init() 
            FirebaseApp.configure()
            if Auth.auth().userAccessGroup == nil 
                do 
                    try Auth.auth().useUserAccessGroup("group.com.****.******")
                 catch let error as NSError 
                    ...
                
            
        
        
        var body: some WidgetConfiguration 
            StaticConfiguration(kind: kind, provider: Provider())  entry in
                WidgetEntryView(entry: entry)
            
        
    

应用代码

    // part of main file
    class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDelegate 
        func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool 
            FirebaseApp.configure()
            ...
            // migrate to shared keychain
            if Auth.auth().userAccessGroup == nil 
                let user = Auth.auth().currentUser
                do 
                    try Auth.auth().useUserAccessGroup("group.com.****.****") // same group
                 catch let error as NSError 
                    ...
                
                // when we switch to app group, user will be set to nil, so
                // if user is logged in, update them in the app group
                if user != nil 
                    Auth.auth().updateCurrentUser(user!)  (err) in
                        if let err = err 
                            print(err.localizedDescription)
                        
                    
                
            
            return true
        
    
    
    // in a viewmodel somewhere else
    Auth.auth().addStateDidChangeListener  [weak self] (auth, user) in
        WidgetCenter.shared.reloadTimelines(ofKind: "my_widget")
        ....
    

【问题讨论】:

【参考方案1】:

文档说明:

注意:共享钥匙串不会跨应用实时自动更新用户。如果您在一个应用中对用户进行了更改,则必须在任何其他共享钥匙串应用中重新加载该用户,然后才能看到更改。

这里有一些代码可以帮助您入门:

func refreshUser() 
    do 
      let currentUser = Auth.auth().currentUser
      let sharedUser = try Auth.auth().getStoredUser(forAccessGroup: accessGroup)
      print("Current user: \(String(describing: currentUser)), shared User: \(sharedUser.uid)")
      if currentUser != sharedUser 
        updateUser(user: sharedUser)
      
    
    catch 
      do 
        try Auth.auth().signOut()
      
      catch 
        print("Error when trying to sign out: \(error.localizedDescription)")
      
    
  
  
  func updateUser(user: User) 
    Auth.auth().updateCurrentUser(user)  error in
      if let error = error 
        print("Error when trying to update the user: \(error.localizedDescription)")
      
    
  

以下代码展示了如何在您的主 SwiftUI 应用程序中使用它,但可以轻松地适应 Widget:

var body: some Scene 
    WindowGroup 
      ContentView()
        .environmentObject(authenticationService)
    
    .onChange(of: scenePhase)  phase in
      print("Current phase \(phase)")
      if let user = Auth.auth().currentUser 
        print("User: \(user.uid)")
      
      else 
        print("No user present")
      
      
      if phase == .active 
        // Uncomment this to refresh the user once the app becomes active
        authenticationService.refreshUser()
      
    
  

【讨论】:

这太好了,谢谢彼得。今天晚些时候我可以测试它后我会接受。如果我从我的 getTimeline() 函数运行 refreshUser() 会很糟糕,还是应该在视图模型中使用它?

以上是关于使用共享用户访问组时,Firebase Auth 用户已过时的主要内容,如果未能解决你的问题,请参考以下文章

Firebase Auth - 自定义声明的用户列表

未设置访问组时共享的钥匙串项目

使用 auth.uid 限制对 Firebase-Database 的访问不起作用

使用 Firebase Auth 访问 Google Calendar API

firebase auth是否可以存储和管理不同提供商的访问令牌?

Firebase - auth.uid 是共享机密吗?