Asked  7 Months ago    Answers:  5   Viewed   36 times

I have a small, personal Firebase webapp that uses Firebase Database. I want to secure (lock down) this app to any user from a single, specific domain. I want to authenticate with Google. I'm not clear how to configure the rules to say "only users from a single, specific domain (say @foobar.com) can read and write to this database".

(Part of the issue that I see: it's hard to bootstrap a Database with enough info to make this use case work. I need to know the user's email at the time of authentication, but auth object doesn't contain email. It seems to be a chicken-egg problem, because I need to write Firebase rules that refer to data in the Database, but that data doesn't exist yet because my user can't write to the database.)

If auth had email, then I could write the rules easily.

Thanks in advance!

 Answers

21

If you're using the new Firebase this is now possible, since the email is available in the security rules.

In the security rules you can access both the email address and whether it is verified, which makes some great use-cases possible. With these rules for example only an authenticated, verified gmail user can write their profile:

{
  "rules": {
    ".read": "auth != null",
    "gmailUsers": {
      "$uid": {
        ".write": "auth.token.email_verified == true && 
                   auth.token.email.matches(/.*@gmail.com$/)"
      }
    }
  }
}

You can enter these rules in the Firebase Database console of your project.

Tuesday, June 1, 2021
 
Lance
answered 7 Months ago
69

Your code isn't far off. Just change your second line to read as follows:

Customer customer = ctx.Customer.FirstOrDefault(c => c.FirstName == "Bobby");
if (customer != null)
{
    //...

Just replace the c.FirstName == "Bobby" with something that can strongly identify the customer you're looking for (e.g. c.Id == customerID if you already know what the ID is).

Saturday, July 31, 2021
 
user972851
answered 4 Months ago
57

The issue is with your onCreate trigger. You assumed you're getting the uid in the context.auth object, which is not correct.

The onCreate trigger will be triggered automatically on the addition of a new document in your "user" collection. In this case, the context.aut.uid is undefined. You should trace this in your function logs.

You can achieve what you are trying to do in a couple of ways

  1. If the user record document has the the user Id as the name of the document, you can do the following
exports.addRegisteredRole =
  functions.firestore
    .document('test/{docId}')
    .onCreate((snap, context) => {
      admin.auth()
        .setCustomUserClaims(snap.id, { isRegistered: true })
        .then(() => {
          console.log('done', snap)
          return {
            message: 'done',
            data: snap
          }
        })
        .catch(err => {
          console.log('something went wrong', err)
          return err
        })
    })
  1. If you're naming the user record document with something else, or letting firebase decide the name for you, then you must have the uid as an attribute in the document data. Then you use docSnapshot.data().uid instead of docSnapshot.id as follows
exports.addRegisteredRole =
  functions.firestore
    .document('test/{docId}')
    .onCreate((snap, context) => {
      admin.auth()
        .setCustomUserClaims(snap.data().uid, { isRegistered: true })
        .then(() => {
          console.log('done', snap)
          return {
            message: 'done',
            data: snap
          }
        })
        .catch(err => {
          console.log('something went wrong', err)
          return err
        })
    })

Good luck

Friday, August 27, 2021
 
Magnanimity
answered 3 Months ago
66

At first glance this seems like a reasonable starting point. I'd just replace the "values that are the same as the key" with a simple true, to save a few bytes of storage/bandwidth. Aside from that it's hard to give more "hard" advice without knowing all use-cases.

You might also want to consider a recent change: security rules can now validate queries, which means that you could potentially do without the /users/$uid/lists index. I recommend that you try this and see if it works for your use-case.

To allow read access to a list only to members of that list, these rules could be a starting point:

{
  "rules": {
    "lists": {
      "$listid": {
        "items": {
          ".read": "
            data.parent().child('members').child('admin').val() === auth.uid ||
            data.parent().child('members').child(auth.uid).exists()
          "
        }
      }
    }
  }
}

The first line of that .read rule grants read access to the admin. The second line then grants read access to all other users.

Finally: as always I recommend reading NoSQL data modeling and watching Firebase for SQL developers.

Sunday, October 3, 2021
 
Xavi
answered 2 Months ago
100

(Sorry for poor english skill ^^;)

Volley is supposed to make downloading and caching images mindlessly simple

YEAH! Volley is VERY SIMPLE. you don't need to think about cache hit, image loading etc...

just use NetworkImageView. Belows are example.

layout_example.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context=".MainActivity">

    <com.android.volley.toolbox.NetworkImageView
            android:id="@+id/photo"
            android:adjustViewBounds="true"
            android:scaleType="fitCenter"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>

</RelativeLayout>

MainActivity.java

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.layout_example);
    NetworkImageView nv = (NetworkImageView) findViewById(R.id.photo);
    nv.setDefaultImageResId(R.drawable.default_image); // image for loading...
    nv.setImageUrl(imageUrl, ImgController.getInstance().getImageLoader()); //ImgController from your code.
}

NetworkImageView automatically loads image from background queue and cancel request when this view is detached using ImageLoader. and ImageLoader automatically uses memory lru cache and disk cache. NetworkImageView is best solution for you.

Additional Information

NetworkImageView
       |
  ImageLoader (uses `LruBitmapCache` you implemented.)
       |
 RequestQueue (uses `DiskBasedCache`. it is already implemented in volley.)
Saturday, October 16, 2021
 
MikeSmithDev
answered 2 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :  
Share