Firebase database not working - ios

I am working on an app that requires Firebase auth and database. When registering, the app must check to see if the code entered is genuine then proceed to create a user. This is my code:
ref = FIRDatabase.database().reference()
self.ref.child("PatientCodes").observeSingleEvent(of: .value, with: { (snaphshot) in
print("In")
let value = snaphshot.value as! NSArray
if value.contains(self.patientIDTextField.text!) {
print("Found ID")
FIRAuth.auth()?.createUser(withEmail: self.emailTextField.text!, password: self.passwordTextField.text!, completion: { (user, error) in
if user != nil {
self.performSegue(withIdentifier: "registered", sender: self)
}
})
}
The issue I am having is, none of the code is being executed past self.ref.child etc. The print("In") statement is never hit.
Any help is greatly appreciated. Thanks in advance.

Before starting anything with Firebase Database,
first check that the rules under database in your console is properly set i.e whether read is true or write is true.

Look at your database's rules, the default rule prevents anonymous read and write, so you must log in first to get access to the database.
{
"rules": {
".read": "auth != null",
".write": "auth != null"
}
}

Related

Firebase Realtime Database doesn't save data from sign up page

I am working on sign up page of application in Swift. The part of authentication in Firebase works well, but the database doesn't save any information I request. Can anyone help?
My code:
Auth.auth().createUser(withEmail: userEmail,password: userPassword, completion: {(User, error) in
if error != nil {
print(error as Any)
return
}
guard let uid = User?.user.uid else {return}
let ref = Database.database().reference(fromURL:"Database-URL")
let userReference = ref.child("users").child(uid)
let values = ["Firstname": userFirstName,"email": userEmail]
userReference.updateChildValues(values, withCompletionBlock: { (error, reference) in
if error != nil {
print(error as Any)
return
}
})
})
The console prints an error
Optional(Error Domain=com.firebase Code=1 "Permission denied"
UserInfo={NSLocalizedDescription=Permission denied})
By default the database in a project in the new Firebase Console is only readable/writeable by authenticated users:
{
"rules": {
".read": "auth != null",
".write": "auth != null"
}
}
See the quickstart for the Firebase Database security rules.
Since you're not signing the user in from your code, the database denies you access to the data. To solve that you will either need to allow unauthenticated access to your database, or sign in the user before accessing the database.
Allow unauthenticated access to your database
The simplest workaround for the moment (until the tutorial gets updated) is to go into the Database panel in the console for you project, select the Rules tab and replace the contents with these rules:
{
"rules": {
".read": true,
".write": true
}
}
This makes your new database readable and writeable by everyone. Be certain to secure your database again before you go into production, otherwise somebody is likely to start abusing it.
I may not be sure but the completion for createUser doesnot give you User and error rather AuthResult and Error. So you have to get the user from result as below
Auth.auth().createUser(withEmail: email, password: password) { (authData, error) in
if let error = error {
debugPrint("FIREBASE ERROR : \(error.localizedDescription)")
} else {
if let authData = authData {
let user = authData.user //here get the user from result
self.saveToDB(user: user) . //save the user to database
}
}
}
This is the new code for firebase from may 2019. just change false to true like this:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if true;
}
}
}

Differentiate between admin and normal User for Firebase (Xcode ios app)

I'm currently developing an IOS app and what i want to do is differentiate between admin users and normal users when logging into the app because at the moment a normal user can log in and get access to the admin options. I'm using Firebase as my database but there's no option to differentiate. Any help would be much appreciated.
Here's my code for login
#IBAction func loginTapped(_ sender: Any) {
if let email = emailTextField.text, let password = passwordTextField.text{
Auth.auth().signIn(withEmail: email, password: password) {(user, error) in
if let firebaseError = error{
print (firebaseError.localizedDescription)
self.showAlert("Invalid Email or Password")
return
}
self.presentLoggedInScreen()
}
}
}
I accept if anyone downvotes this post but please comment below why you doing so. Thanks
You need to use other things to implement some role based authentication, you can check examples here to give you some ideas: https://firebase.google.com/docs/auth/admin/custom-claims
You can add rules to your Firebase database:
Got to your database on your Firebase console then click on your Rule Tab on you right side and add one of the following examples adapted to your code.
For example, here everyone has access to your /foo/ path but no one can write to it:
service cloud.firestore{
"rules": {
"foo": {
".read": true,
".write": false
}
}
}
So, if you want a certain autoriztion to some path for determinated users you can do it as follows:
service cloud.firestore{
"rules": {
"users": {
"$uid": {
"foo": {
".read": true,
".write": false
}
}
}
}
}
Or you can do it with a parameter to restrict foo access to a specific uid:
"foo":{
".read": "auth.uid != null &&
query.orderByChild == 'owner' && query.equalTo == auth.uid"
}

How do I validate if a username exists before sign up in Firebase and Swift 3?

I've incorporated a sign-up flow of five view controllers as opposed to one central VC for Firebase sign up.
Normally there would be the problem of data being lost before sign up, but I'm pushing all the entered values via segue programmatically to the final confirmation page and sending the data to Firebase for auth eventually.
My problem lies therein - I want to check if the username exists before signing up. This is imperative for the UX of my app and I can't just do this all one VC.
Here's the code I have for the UsernameViewController:
let rootRef = FIRDatabase.database().reference()
rootRef.queryOrdered(byChild: "users").queryEqual(toValue: self.chooseUsernameTextField.text!)
.observe(FIRDataEventType.value, with: { (snapshot: FIRDataSnapshot!) in
if snapshot.hasChildren() == false {
print("not found")
} else {
print("usr found")
}
});
Here's the code I have for the Firebase Database Security Rules
{
"rules": {
".read": false,
".write": false,
"users": {
".validate": "data.child('username').val() === true",
".read": true
}
}
}
and finally, a screenshot of my Data tree (My Data tree won't let me nest any new users or create a user node without a value for some reason):
Picture of Firebase Data Tree: App Name/Users
I have a nagging suspicion that my data rules and tree are configured properly to match the code, but I'm stuck in a XY problem of not knowing what to do for Firebase security to get my code of username checking complete.
Please help me! :(
If there's a user created within the Auth section of Firebase as well, then you can actually use the fetchProviders method, and if no providers are returned, you have no user in you Auth section.
FIRAuth.auth()?.fetchProviders(forEmail: email, completion: { (providers, error) in
if providers == nil {
// user doesn't exist
} else {
// user does exist
}
})
I have not tested the code but the theory would be to order by username that equals to the username you are looking for. If this snapshot exists you already have a user in the database with that name if it doesn't you do not.
Will run and test code when i have a chance to and update my post.
let rootRef = FIRDatabase.database().reference()
rootRef.child("users").queryOrdered(byChild:"username").queryEqual(toValue: self.chooseUsernameTextField.text!)
.observe(.value, with: { (snapshot) in
if snapshot.exists() == false {
print("not found")
} else {
print("usr found")
}
});
When using Firestore to save users, I did this
Auth.auth().addStateDidChangeListener({ (auth, user) in
if let id = user?.uid{
let userDoc = db.collection("users").document(id)
userDoc.getDocument { (document, error) in
if document == nil{// if user doesn't exist, create one
self.db.collection("users").document(id).setData(userProfile.toDictionary()){ error in
}
}
}
}
})

Firebase,Swift : Not able to retrieve Data

I'm trying to do a simple task, to get a value from Firebase.
I added the image below with the relevant screens. At least one of the print commands should print a message to the console, but it's not working. I've been trying to fix it for 1,5 days now and I still have no idea why it is not working.
Code:
import UIKit
import Firebase
class MainVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let ref = FIRDatabase.database().reference()
ref.child("zonneschijn").observeSingleEventOfType(.Value, withBlock: { snapshot in
if snapshot.value is NSNull {
print("Does not exist currently")
} else {
print("Exists currently")
}
})
}
}
I've also tried to use viewDidAppear, also with no succes.
If you are not authenticating your user's.
Go to Rules tab in Realtime Database in Firebase console.
Default Security rules of firebase are something like this :-
{
"rules": {
".read": "auth != null",
".write": "auth != null"
}
}
Which means only authenticated users(Those user's who have been signed in either with gmail, Facebook, gitter, email..etc) can read or write data...
Clearly you are not authenticating your user that's why you can not retrieve any data with these default Security Rules .
This is a good practice to only allow authenticated users to have access to the DB, as it is more secure.If you want to read data anyways , Modify your security rules to this:-
Warning :- Not Recommended if you are making app that has some private DB.
// These rules give anyone, even people who are not users of your app,
// read and write access to your database
{
"rules": {
".read": true,
".write": true
}
}
A better alternative :-
Sign in your user(start with email-password : Firebase EMAIL- Password Auth)
Then access your DB
Do read : Security Rule's

Query users in Firebase to check if username exists during sign up process [duplicate]

This question already has an answer here:
Swift & Firebase | Checking if a user exists with a username
(1 answer)
Closed 6 years ago.
Question
How do I check if a username already exists during the user sign up process?
I don't know how to query Firebase to determine if a specific value exists.
Background
Firebase structure:
Users
0BBfrF1vVBXXxNxeVMes9MFkYNJ3
name: "SAM"
0oU9sf7CZxaDBx03t87lqTrv9UM2
name: "JACK"
IsXEqXov0obuwl1WOrHhCbfdfEo1
name: "JEREMY"
In the code below:
I attempt to check if value usernameField exists in: users\userID\name
child(userID) doesn't retrieve anything
_
let username = self.usernameField.text
let userRef = ref.child("Users").child(userID).child("name")
userRef.observeEventType(.Value, withBlock: { snapshot in
if snapshot.value!.isEqual(username) {
print("snapshot exists")
} else {
print("snapshot doesnt exist")
}
userRef.removeAllObservers()
}, withCancelBlock: { error in
print(error)
})
There is a pretty easy way on doing this.
Since you are using removeAllObservers right after the the first callback I'm assuming that you might take a look on using observeSingleEventOfType and you wont need to turn any observer later.
let username = self.usernameField.text
ref.child("Users").queryOrderedByChild("name").queryEqualToValue(username).observeSingleEventOfType(.Value, withBlock: { (snapshot) in
if snapshot.exists == true {
print("snapshot exists")
} else {
print("snapshot doesnt exist")
}
}) { (error) in
print(error.localizedDescription)
}
You should also write some database rules to guarantee the data consistency and performance in the server side. From the current structure you have this wont be straight-forward since you don't have the username as the key for your Users branch.
So I can see two possible solutions:
Username as the key
Saving the username as the /Users key you will just have a rule to enforce this key uniqueness.
{ "rules": {
"Users": {
".indexOn":
".write": "true",
"$username": {
".validate": "!root.child('Users').hasChild($username)"
}
}
}}
This would need some changes on your application code to see if this already exists
ref.child("Users").child(username).observeSingleEventOfType(.Value, withBlock: { (snapshot) in
if snapshot.exists == true {
print("snapshot exists")
} else {
print("snapshot doesnt exist")
}
}) { (error) in
print(error.localizedDescription)
}
Create a new branch to handle the username uniqueness
You want to keep the same structure you have today you will need to do some other changes. Just like the question that Frank linked you will need an extra branch only to store all the taken usernames. So whenever saving a new user you will need to first store the username in this other branch.
{ "rules": {
"Users": {
".indexOn": "name",
".write": "true",
"$id": {
".validate": "!root.child('already_taken_names').hasChild(newData.child('name').val())"
}
},
"already_taken_names": {
"$username": {
".validate": "!root.child('Users').hasChild($username)"
}
}
}}

Resources