2016-07-14 2 views
1

Я использую Firebase 3.0 и Swift v2.2. Я столкнулся с проблемой при использовании Firebase sendPasswordResetWithEmail, чтобы пользователи могли сбросить свои пароли в моем приложении iOS. Проблема в том, что адрес сброса пароля отправляется всем пользователям, даже тем пользователям, которые изначально не вошли в систему с Firebase, а вместо этого использовали кнопку входа в систему Google или кнопку входа в систему Facebook, также доступную в моем приложении. К сожалению, даже если пользователь получает электронное письмо и выполняет инструкции по сбросу пароля, ссылка, указанная в электронном письме с сбросом пароля, сбрасывает пароль только для тех учетных записей, которые вошли в систему Firebase; он не сбрасывает свой пароль Google или Facebook. Таким образом, они по-прежнему не смогут войти в систему.Разрешение при чтении провайдера (т. Е. Google, Facebook, Firebase), первоначально используемого для аутентификации пользователя Firebase 3.0

Мое решение было реализовать функцию getAuthProvider() (показано в коде, представленной ниже), чтобы получить первый поставщик, который я храню в мой пользователь узел в базе данных реального времени (как показано ниже), и в зависимости от поставщика я затем отправляю запрос на сброс пароля или покажу пользователю сообщение об ошибке, в котором говорится, что они должны сбросить пароль с помощью соответствующего провайдера.

Однако queryEqualToValue вызов возвращается к ошибке Permission Denied. Я обновил правила в своей базе данных реального времени Firebase (как показано ниже). Обратите внимание, так как пользовательские сброс своих паролей не являются аутентифицированными пользователями в то время, когда они запрашивают сброс пароля, я хотел бы предоставить им как можно меньше доступа. Я не хочу разрешать им получать доступ к имени и фамилии пользователя, я бы предпочел только предоставить им доступ к чтению провайдера. Что мне не хватает? Спасибо за любой вклад!

Firebase иерархия:

  • пользователя
    • UID
      • электронный
      • Firstname
      • Lastname
      • поставщик [значение s: «Firebase» или «Google.com» или «Facebook».ком "]

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); 

    } 
} 

ответ

0

Если я уменьшить свой вопрос, этот код:

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>). Чтение не удастся, так как вы не предоставляете доступ. См. rules are not filters в документации Firebase.
Смежные вопросы