Read and Write rules In a proper way Firebase - ios

How can I test if a username exists in the proper way? This code is not working. Do I have to update my rules in some sort of way? Im not too familiar with firebase rules.
Rules:
{
"rules": {
"Users":{
".read": "true",
".write": "true"
}
}
}
Current JSON Tree Setup:
+Users
+iq5oM0XlgAa9K78EuEFdZ0ZVTsm1
Email: "test#gmail.com"
Name: "jj"
Password: "***"
Username: "jjj"
CODE:
let username : String = self.usernameField.text!
//Checking username existence
FIRDatabase.database().reference().child("Users/Username").child(username).observeSingleEvent(of: .value, with: {(usernameSnap) in
if usernameSnap.exists(){
//This username already exists
print("The user name already exists")
}else{
//Yippee!.. This can be my username
print("user good to go")
print(username)
}
})

You need to make a separate node in your database called usernames. Here you save the username as the key, and the userID as the value. Now you can check the usernames node to see if a username already exists.

Related

SwiftUI Edit User Account using data from Firestore

I'm very new to SwiftUI and I'm trying to create a very basic login/logout system in SwiftUI on IOS with the ability to edit the users profile. I have two main functions in the signup process, function register and function AddInfo which then actually adds the user to the db.
both in AuthenticationView.swift
func register(){
if self.email != ""{
if self.pass == self.repass{
//Creating the user
Auth.auth().createUser(withEmail: self.email, password: self.pass) { (res, err) in
if err != nil{
self.error = err!.localizedDescription
self.alert.toggle()
return
}
//Add user info to database
AddInfo(username: self.username, email: self.email)
print("success")
UserDefaults.standard.set(true, forKey: "status")
NotificationCenter.default.post(name: NSNotification.Name("status"), object: nil)
}
}
else{
self.error = "Password mismatch"
self.alert.toggle()
}
}
else{
self.error = "Please fill all the contents properly"
self.alert.toggle()
}
}
Then i have an addinfo function which adds the user to a database. The document ID of the db is the users UID and then it creates a username, email and uid automatically and i've made it create a blank entry for Firstname and Lastname.
func AddInfo(username: String, email: String) {
let db = Firestore.firestore()
let user = Auth.auth().currentUser
if let user = user {
// The user's ID, unique to the Firebase project.
// Do NOT use this value to authenticate with your backend server,
// if you have one. Use getTokenWithCompletion:completion: instead.
let uid = user.uid
//let email = user.email
//let photoURL = user.photoURL
db.collection("users").document(uid).setData([
"UID": uid,
"Username": username,
"Email": email,
"First Name": "",
"Last Name": ""])
}
This is what the DB looks like when a user registers
database look when user registers
So with all of this in mine, i'm struggling with creating a Edit user profile view. How would I go about doing this? All i need is a page that shows the users registered email, username and then they can add their first and last name (first and last name isn't included on the registration form, that's something i'd like to add after they've registered)
I've tried reading the Firestore view my profile document but i'm struggling to get my head around it

Checking username before signing up Firebase

After using snapshot.exists(), username will always return as available upon signup. How can I alter my code to properly check whether or not a username has already been taken?
Here is a snippet of the json under "users" in the database:
{
"UserID#" : {
"credentials" : {
"name" : "testuser",
},
}
}
My code currently looks like:
let usersDB = Database.database().reference()
var taken = false
usersDB.child("users").child("credentials").queryOrdered(byChild:"name").queryEqual(toValue: username.lowercased()).observeSingleEvent(of: .value, with: { (snapshot) in
if snapshot.exists() {
taken = true
print("Username is not available.")
usernameAlert()
} else {
print("User is available")
}
No matter if the username is already taken on the database, the snapshot will say it does not exist.
Solutions I've tried with no success:
check if the username exist in Firebase
Query users in Firebase to check if username exists during sign up process
Firebase querying for unique Username swift
Check if user exists with username using Swift and Firebase
Swift & Firebase | Checking if a user exists with a username
You're now checking under each child node of /users/credentials for a property named name. What you instead want is to check each child node of /users for a property at credentials/name, which you do with:
usersDB.child("users").queryOrdered(byChild:"credentials/name").queryEqual(toValue: ...

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

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