【问题标题】:Permission issue while reading the provider(i.e.Google,Facebook,Firebase) originally used to authenticate user to Firebase 3.0读取最初用于向 Firebase 3.0 验证用户身份的提供程序(即 Google、Facebook、Firebase)时的权限问题
【发布时间】:2016-11-16 18:45:55
【问题描述】:

我正在使用 Firebase 3.0 和 Swift v2.2。我在使用 Firebase 的 sendPasswordResetWithEmail 允许用户在我的 iOS 应用中重置密码时遇到了问题。问题是密码重置电子邮件会发送给所有用户,即使是那些最初没有使用 Firebase 登录而是使用 Google 登录按钮或 Facebook 登录按钮的用户也可以在我的应用程序中使用。不幸的是,即使用户收到电子邮件并按照说明重置密码,密码重置电子邮件中提供的链接也只会重置那些使用 Firebase 登录的帐户的密码;它不会重置他们的 Google 或 Facebook 密码。因此,他们仍然无法登录。

我的解决方案是实现函数 getAuthProvider()(如下面提供的代码所示)以首先获取我保存在我的 中的提供程序实时数据库中的用户节点(如下所示),然后根据提供商发送密码重置请求或向用户显示一条错误消息,说明他们必须使用适当的提供商重置密码。

但是,queryEqualToValue 调用返回错误 Permission Denied。我更新了 Firebase 实时数据库中的规则(如下所示)。请注意,由于用户在请求重置密码时是未经身份验证的用户,因此我希望尽可能少地给他们访问权限。我不想让他们访问用户的名字和姓氏,我宁愿只让他们访问读取提供程序。我错过了什么?感谢您的任何意见!

Firebase 层次结构:

  • 用户
    • uid
      • 电子邮件
      • 名字
      • 姓氏
      • 提供者 [值:“Firebase”或“Google.com”或“Facebook.com”]

Firebase 规则:

{
  "rules": {
    ".read": "auth != null",
    ".write": "auth != null",
    "user": {
      "uid": {
        "$provider": {
          ".read": true,
          ".write": "auth != null"
        }
      }
    }
  }
}

ViewController 代码:

import UIKit
import Firebase

class ResetPasswordTableViewController: UITableViewController, UITextFieldDelegate {

    @IBOutlet weak var emailTextField: UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()

        //Hide navigation bar
        self.navigationController?.navigationBarHidden = true

        //Text fields delegates
        self.emailTextField.delegate = self
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    //--------------------------------------------------------
    // MARK: Hide status bar
    //--------------------------------------------------------
    override func prefersStatusBarHidden() -> Bool {
        return true
    }

    @IBAction func resetPasswordButtonTapped(sender: AnyObject?) {

        //Set user fields
        let email = emailTextField.text

        // Check for empty fields
        if (email!.isEmpty)
        {
            // Display error message
            displayAlertMessage(REQUIRED_FIELDS_ERROR_TITTLE, message: REQUIRED_FIELDS_ERROR_MESSAGE)

            return;
        }

        // Validate email address
        if !(UserAccountValidator.validateEmailTextField(email!)) { //if invalid email format
            // Display error message
            self.displayAlertMessage(REENTER_EMAIL_ERROR_TITLE, message: REENTER_EMAIL_ERROR_TITLE)
            return
        }

        // Get the current user's provider, only those users who were authenticated with Firebase as the provider should be sent a reset password email
        let authProvider = getAuthProvider(email!)
        if (!authProvider.isEmpty && authProvider == "Firebase") {
            FIRAuth.auth()?.sendPasswordResetWithEmail(email!) { error in
                // Back to main thread
                NSOperationQueue.mainQueue().addOperationWithBlock {
                    if  error != nil {
                        if let errorCode = FIRAuthErrorCode(rawValue: error!.code) {
                            switch (errorCode) {
                            case .ErrorCodeUserNotFound:
                                self.displayAlertMessage(EMAIL_NOTFOUND_3RDPARTY_ERROR_TITLE, message: EMAIL_NOTFOUND_3RDPARTY_ERROR_MESSAGE);
                                return
                            default:
                                self.displayAlertMessage(ACCOUNT_CREATION_DB_ERROR_TITLE, message: ACCOUNT_CREATION_DB_ERROR_MESSAGE);
                                return
                            }
                        }
                    } else {
                        // Present reset password success view
                        self.performSegueWithIdentifier("resetPasswordSuccessView", sender: self)
                    }
                }
            }
        } else {
            // Display error message
            displayAlertMessage("Authentication Provider Mismatch", message: "It looks like you originally signed in with this email using Google or Facebook. Please reset your password with the appropriate provider and then come back and sign in with your new password.")
        }
    }

    //--------------------------------------------------------
    // MARK: Local Methods
    //--------------------------------------------------------
    func getAuthProvider(email: String) -> String {
        //Retrieve Authentication Provider for a given UID
        var authProvider: String = ""
        FIRDatabase.database().reference().child("user").queryEqualToValue(email).observeSingleEventOfType(.Value, withBlock: { (snapshot) in
            // Get user value
            authProvider = snapshot.value!["provider"] as! String
        }) { (error) in
            print(error.localizedDescription)
        }
        return authProvider
    }

    //--------------------------------------
    // MARK: - Display Error Message Methods
    //--------------------------------------
    func displayAlertMessage(title:String,message:String)
    {
        let alertMessage = UIAlertController(title: title, message: message, preferredStyle:UIAlertControllerStyle.Alert);

        let okAction = UIAlertAction(title:"OK", style: .Default, handler:nil);

        alertMessage.addAction(okAction);

        self.presentViewController(alertMessage, animated: true, completion: nil);

    }
}

【问题讨论】:

    标签: ios swift firebase


    【解决方案1】:

    如果我减少你的问题,这段代码:

    FIRDatabase.database().reference().child("user").queryEqualToValue(email).observeSingleEventOfType(.Value, withBlock: { (snapshot) in
    

    使用以下规则无法读取未经身份验证的用户:

    {
      "rules": {
        ".read": "auth != null",
        ".write": "auth != null",
        "user": {
          "uid": {
            "$provider": {
              ".read": true,
              ".write": "auth != null"
            }
          }
        }
      }
    }
    

    两件事:

    1. 您的规则中的uid 是一个文字字符串。要使其下的规则适用于user 的每个子节点,名称应以$ 开头,例如$uid$email(实际名称无关紧要:如果它以 $ 开头,则它是通配符/变量)。
    2. 您的规则中有uid,但传入了一个名为email 的变量。我不确定它们是否匹配,但听起来很奇怪。
    3. 您正在尝试读取特定用户 (/user/<myuid>),但仅授予对 $provider (/user/<myuid>/<provider>) 的公共读取访问权限。读取将失败,因为您不授予访问权限。请参阅 Firebase 文档中的 rules are not filters

    【讨论】:

      猜你喜欢
      • 2020-06-07
      • 1970-01-01
      • 2020-02-20
      • 2018-01-24
      • 2019-10-10
      • 2018-02-25
      • 1970-01-01
      • 2017-04-16
      • 1970-01-01
      相关资源
      最近更新 更多