I have a simple database structure that i want to add firebase security rules to but the rules is blocking all the permission even when i set the value of .read and .write to true under the node structure, Here is the sample of the rule
{
"rules": {
"Lines": {
".read": true,
".write": false
},
"Links": {
".read": true,
".write": false
}
}
}
Here is a Sample of My Database Structure
{
"Lines" : {
"Line 1" : "Lines 1238443",
"Line 2" : "Lines 4657673"
},
"Links" : {
"Links 1" : "Link 3282873",
"Links 2" : "Link 3493934"
}
}
I am trying to allow only read operations but my application keeps saying permission is denied i have check the documentation it looks straight forward but i can't tell what exactly is happening because even when i tried
{
"rules": {
"Lines": {
".read": true,
".write": true
},
"Links": {
".read": true,
".write": true
}
}
}
I still get permission denied error
Here is the code to read from the database
DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference();
databaseReference.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
String lin = snapshot.child("Links").child("Links 1").getValue(String.class);
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
Toast.makeText(getApplicationContext(), "Error "+error.getMessage(), Toast.LENGTH_SHORT).show();
}
});
You're trying to read from the root of the database. And since your rules don't grant anyone read access to the root of the database, the read is rejected.
If you only want to read the Links child from the database, you should specify that child name before attaching a listener, so:
DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference();
databaseReference.child("Links").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
String lin = snapshot.child("Links 1").getValue(String.class);
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
Toast.makeText(getApplicationContext(), "Error "+error.getMessage(), Toast.LENGTH_SHORT).show();
}
})
Now we're attaching a listener to /Links, where the security rules do allow reading the data.
Related
Every time the user retrieves the Firebase Realtime Database messages, he would like only the last 50 messages from the messaging node to be retrieved (read) through the Realtime Database rules. How to do this?
Message node structure:
+ chats
+ regionChat (ex: eua)
+ idChat (ex: 534854923)
+ messages
+ idMessage1
+ idMessage2
+ idMessage3
+ idMessage4
+ idMessage5
...
I saw this in the firebase documentation, but I can't adapt my data structure:
messages: {
".read": "query.orderByKey &&
query.limitToFirst <= 50"
}
At the moment my rules are like this:
{
"rules": {
".read": true,
".write": true
}
}
you need to enhance your "query"
this should work
{
"rules": {
".read": "query.limitToFirst <= 50",
".write": true
}
}
Or, instead of using the rules, you can do it via Query.
DatabaseReference myReference = FirebaseDatabase.getInstance().getReference();
myReference = myReference().child("chats")...child("messages");
Query query = myReference.orderByID().limitToFirst(20).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
//
for (DataSnapshot issue : dataSnapshot.getChildren()) {
// do something with the data
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
So I have a simple booking system where I allow users to reserve tickets using Firebase. I'm using transactions to avoid concurrency issues.
Basically this is the structure of the DB:
TerminalID:
BussID:
SeatID:
TempEmail:
So this is an example where I want to book seats for bus number 1. seatList is the list of seats with seatIDs that the user wants to book. And for reserving the booking, I add a temporary email to the seatID.
DatabaseReference postRef = mDatabase.child("terminal").child("1");
postRef.runTransaction(new Transaction.Handler() {
#Override
public Transaction.Result doTransaction(MutableData mutableData) {
if(mutableData.getValue() == null){
return Transaction.success(mutableData);
}
for (int i = 0; i < seatList.size(); i++) {
if (mutableData.child(Integer.toString(seatList.get(i))).child("tempEmail").getValue() == null) {
mutableData.child(Integer.toString(seatList.get(i))).child("tempEmail").setValue(mUser.getEmail());
}
else{
Transaction.abort();
}
}
return Transaction.success(mutableData);
}
#Override
public void onComplete(DatabaseError databaseError, boolean b, DataSnapshot dataSnapshot) {
progressBar.setVisibility(View.INVISIBLE);
// Transaction completed
if (b == true){
Toast.makeText(getContext(), "Success!",
Toast.LENGTH_SHORT).show();
}
else {
Toast.makeText(getContext(), "Someone just reserved them!", Toast.LENGTH_SHORT).show();
}
}
});
Rules:
"terminal": {
".read": true,
//".write": "root.child('users').child(auth.uid).child('role').val() === 'admin'",
"$bid": {
"$sid": {
"uid": {
".write": "data.val() === 'null' || data.val() === auth.id"
},
"tempEmail": {
".write": "auth != null"
},
"booked": {
".write": false
},
"email": {
".write": false
}
}
}
},
However, I get a permission denied error. I've double checked the rules, and I have allowed anyone to write just to make sure that it wasn't the rules. I suspect that this is because I'm trying to update more than 1 child node? However I've also attempted to book only 1 seat and this error still occurs. So I'm thinking it may be because I'm trying set the value of a child node, which is perhaps not allowed. Or there is perhaps something wrong with my code in general?
EDIT: I made a mistake, it does work when I set write = true to the top of the JsonObject.
I am trying to get all emails of users using firebase Query like below
private void searchUserByEmail(final String searchText) {
DatabaseReference mFirebaseDatabaseReference = FirebaseDatabase.getInstance().getReference();
Query query = mFirebaseDatabaseReference.child(Constants.FB_TABLE_USERS).orderByChild(Constants.FB_EMAIL).equalTo(searchText);
query.addListenerForSingleValueEvent(new ValueEventListener() {
}}
And While Searching Any email Which is not in list I am getting a warning message in my console Like
W/PersistentConnection: pc_0 - Using an unspecified index. Consider adding '".indexOn": "email"' at table_users to your security and Firebase Database rules for better performance
And My Rules in FireBase is
{
"rules": {
".read" : "auth != null",
".write" : "auth != null",
"table_users": {
".indexOn": ["email"]
}
}
}
This is my Users Table screenshot
you should remove the brackets from ".indexOn" value
"table_users": {
".indexOn": "email"
}
query.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
String email = snapshot.child("email").getValue();
System.out.print(email);
}
}
});
I am working on an android project that requires user email and pwd authentication. The details are stored in the firebase database.The problem occurs whenever I try logging in again with the email and password. In my logcat the error message is:
W/SyncTree: Listen at / failed: DatabaseError: Permission denied
Take a look at my code below:
public class LoginUser extends AppCompatActivity {
private RelativeLayout relativeLayout;
private EditText et_email, et_password;
private Button loginBtn;
private FirebaseAuth mAuth;
private FirebaseAuth.AuthStateListener authStateListener;
private DatabaseReference databaseReference;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login_user);
mAuth = FirebaseAuth.getInstance();
databaseReference = FirebaseDatabase.getInstance().getReference();
databaseReference.keepSynced(true);
relativeLayout = (RelativeLayout) findViewById(R.id.activity_login_user);
et_email = (EditText) findViewById(R.id.emailField);
et_password = (EditText) findViewById(R.id.pwdField);
loginBtn = (Button) findViewById(R.id.loginBtn);
loginBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
initLogin();
}
});
authStateListener = new FirebaseAuth.AuthStateListener() {
#Override
public void onAuthStateChanged(#NonNull FirebaseAuth firebaseAuth) {
if (firebaseAuth.getCurrentUser() != null){
initLogin();
}
else {
startActivity(new Intent(LoginUser.this,RegisterFireBase.class));
}
}
};
}
#Override
protected void onStart() {
super.onStart();
mAuth.addAuthStateListener(authStateListener);
}
#Override
protected void onStop() {
super.onStop();
if (mAuth != null){
mAuth.removeAuthStateListener(authStateListener);
}
}
private void initLogin() {
String email = et_email.getText().toString().trim();
String pass = et_password.getText().toString().trim();
if (!TextUtils.isEmpty(email) && !TextUtils.isEmpty(pass)){
mAuth.signInWithEmailAndPassword(email,pass).addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
checkForUser();
}
});
}
else {
Toast.makeText(this, "Some fields are empty", Toast.LENGTH_SHORT).show();
}
}
private void checkForUser() {
final String userId = mAuth.getCurrentUser().getUid();
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.hasChild(userId)){
Intent loginIntent = new Intent(LoginUser.this, FireProfile.class);
loginIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(loginIntent);
Snackbar.make(relativeLayout,"Log In Successful",Snackbar.LENGTH_LONG).show();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
}
What could be causing this?
Possible reason could be : you dont have read and write access on your database.
For enabling read and write access :
Go to firebase console and enable read and write operations on your database.
Firebase Console -> Database(develop) -> RULES
{
"rules": {
".read": "true",
".write": "true"
}
}
Do not put you app public if this is not needed.
As described on google documentation you can do these rules on your firebase > database > rules
// These rules grant access to a node matching the authenticated
// user's ID from the Firebase auth token
{
"rules": {
"users": {
"$uid": {
".read": "$uid === auth.uid",
".write": "$uid === auth.uid"
}
}
}
}
or to let only authenticated users
// These rules require authentication
{
"rules": {
".read": "auth != null",
".write": "auth != null"
}
}
Letting an app public let anyone write and read your app... i don't think any app should use this like that.
Go to the Rules tab on your Database console. If you have not explicitly granted .read access to your user then permission will be denied.
This link is excellent in the Firebase doc:
https://firebase.google.com/docs/database/security/securing-data
These two notes on that page are of particular interest:
Note: Access is disallowed by default. If no .write or .read rule is specified at or above a path, access will be denied.
Note: Shallower security rules override rules at deeper paths. Child rules can only grant additional privileges to what parent nodes have already declared. They cannot revoke a read or write privilege.
Review the node where permission is being denied and use the Simulator on the Rules tab in order to test your rules for different user security contexts (non-authenticated, authenticated, etc.)
Do some changes on firebase database.
go to firebase -> Database -> rules
{
"rules":
{
".read": true,
".write": true
}
}
Most answers are simply suggesting making the database access to anyone to read and edit. This may be acceptable for rough testing, but certainly not for anything serious.
Google Firebase allows configuration to allow and deny access. Read the official documentation here:
https://firebase.google.com/docs/rules/basics#realtime-database
(Make sure to select the right type of Firebase database)
For anything requiring authentication, you will need to set up Firebase auth: https://firebase.google.com/docs/auth
Here are some basic examples:
No access (default)
{
"rules": {
".read": false,
".write": false
}
}
Authenticated Users Only
{
"rules": {
".read": "auth.uid != null",
".write": "auth.uid != null"
}
}
Read Public, Write by Owner Only
{
// Allow anyone to read data, but only authenticated content owners can
// make changes to their data
"rules": {
"some_path": {
"$uid": {
".read": true,
// or ".read": "auth.uid != null" for only authenticated users
".write": "auth.uid == $uid"
}
}
}
}
Please try to change your firebase rules like below I faced this problem previously.
My problem was in database rules:
{
"rules": {
".read": "true",
".write": "true"
}
}
the problem is that the firebase database has two projects with the same name and one of the project's rules are not even enabled
So see on all projects once
Go to firebase console and enable read and write operations on your database.
Firebase Console -> Database(develop) -> RULES
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write: if request.auth != null;
}
}
}
if you are using the old version add the following rule,
{
"rules": {
".read": "true",
".write": "true"
}
}
My Firebase storage looks like this -
{
notes: {
note_1: {
$uid: 0 | 1,
title: "",
description: "",
priority: "",
state: "",
time: 0
},
note_2: {
...
}
}
}
where $uid is the user id.
I have configured my rules like this -
{
"rules": {
"notes": {
"$note_id": {
".read": "data.child(auth.uid).exists()",
".write": "(auth != null && !data.exists()) || data.child(auth.uid).val() === 1"
}
}
}
}
Now, I want to query all the notes for a particular user. I tried with the below code -
mDatabase.child("notes").orderByChild(getLoggedInUserId())
.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Log.d(getClass().getCanonicalName(), Long.toString(dataSnapshot.getChildrenCount()));
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
However, this does not work, as I don't have read permission on "notes".
Can anyone advise what should be done to retrieve data like this?
Change orderByChild for child
mDatabase.child("notes").child(getLoggedInUserId()