【发布时间】: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”]
- uid
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);
}
}
【问题讨论】: