Firestore permission denied when using signInWithC

2019-06-01 19:24发布

    firebase.initializeApp(config);
    const db = firebase.firestore();

   const googleSignIn = async () => {
        return await Expo.Google.logInAsync({
            androidClientId,
            iosClientId,
            scopes: ['profile', 'email'],
        });
    };

    const firebaseLogin = async (accessToken) => {
        const cred = firebase.auth.GoogleAuthProvider.credential(null, accessToken);
        await firebase.auth().signInWithCredential(cred).catch(console.error);
        const idToken = await firebase.auth().currentUser.getIdToken(true).catch(console.error);
    };

await firebaseLogin(googleSignIn().accessToken);
db.collection("any").doc().set({test: "OK"})

I get a permission denied error when trying to write to Firestore using a request.auth.uid != null; security rule, but when I replace it with true it works.

It seems that the Firestore component of the web SDK does not send authentication details, even though the API on the client reports Firebase is logged in, and the user last login date appears in the web GUI.

Do I need to pass authentication details to the Firestore component when logging in directly with Google (instead of using the Firebase login APIs)?

The code is running in a React Native app via Expo.

Another example that gets a permission denied:

firebase.auth().onAuthStateChanged((user) => {
    if (user) {
        firebase.firestore().collection("any").doc().set({test: "OK"});
    }
});

Rules

// This is OK:
    service cloud.firestore {
      match /databases/{database}/documents {
        match /any/{doc} {
            allow read, write: if true;
        }
      }
    }

// Permission denied
    service cloud.firestore {
      match /databases/{database}/documents {
        match /any/{doc} {
            allow read, write: if  request.auth.uid != null;
        }
      }
    }

Related

1条回答
Luminary・发光体
2楼-- · 2019-06-01 19:59

This solution, and possibly this whole issue, may be specific to React Native.

In a similar question, Jade Koskela noticed that requests were missing the Origin header, and applies a patch to React's XHRInterceptor to work around the missing auth object:

const xhrInterceptor = require('react-native/Libraries/Network/XHRInterceptor');
xhrInterceptor.setSendCallback((data, xhr) => {
  if(xhr._method === 'POST') {
    // WHATWG specifies opaque origin as anything other than a uri tuple. It serializes to the string 'null'.
    // https://html.spec.whatwg.org/multipage/origin.html
    xhr.setRequestHeader('Origin', 'null');
  }
});
xhrInterceptor.enableInterception();
查看更多
登录 后发表回答