Настройка пользовательских утверждений для аутентификации Firebase от флаттера - PullRequest
1 голос
/ 17 марта 2020

Я использую Firebase auth для приложения, но как часть создания пользователя мне нужно установить некоторые пользовательские утверждения.

Я написал облачную функцию для установки утверждений когда пользователь создан:

    const functions = require('firebase-functions');
    const admin = require('firebase-admin');
    admin.initializeApp(functions.config().firebase);

    // On sign up.
    exports.processSignUp = functions.auth.user().onCreate(user => {

    let customClaims;

    // Set custom user claims on this newly created user.
    return admin.auth().setCustomUserClaims(user.uid, {
            'https://hasura.io/jwt/claims': {
                'x-hasura-default-role': 'user',
                'x-hasura-allowed-roles': ['user'],
                'x-hasura-user-id': user.uid
            }
        })
        .then(() => {
            // Update real-time database to notify client to force refresh.
            const metadataRef = admin.database().ref("metadata/" + user.uid);
            // Set the refresh time to the current UTC timestamp.
            // This will be captured on the client to force a token refresh.
            return metadataRef.set({
                refreshTime: new Date().getTime()
            });
        })
        .then(() => {
            return admin.auth().getUser(user.uid);
        })
        .then(userRecord => {
            console.log(userRecord);
            return userRecord.toJSON();

        })
        .catch(error => {
            console.log(error);
        });
});

Когда я распечатываю на консоль userRecord, я вижу, что настраиваемые утверждения установлены правильно.

Затем во флаттере я получаю токен из созданного пользователь, но тогда кажется, что к нему не прикреплены пользовательские заявки.

Я использую этот код для создания пользователя и распечатки заявок в флаттере

    Future<FirebaseUser> signUp({String email, String password}) async {
    final FirebaseUser user = (await auth.createUserWithEmailAndPassword(
      email: email,
      password: password,
    )).user;

    IdTokenResult result = await (user.getIdToken(refresh: true));
    print('claims : ${result.claims}');

    return user;
  }

Если я проверяю сам токен в отладчике jwt, который я вижу, у него нет пользовательских требований к нему. Неужели мне нужны дополнительные шаги, чтобы попытаться получить обновленный токен после того, как были установлены претензии? Я пробовал user.reload() и user.getIdToken(refresh: true), но, похоже, они не помогают.

Есть идеи, как получить токен с пользовательскими утверждениями?

Ответы [ 2 ]

4 голосов
/ 17 марта 2020

Код, который вы показываете, скорее всего пытается получить пользовательские претензии слишком рано после создания учетной записи. После вызова auth.createUserWithEmailAndPassword функция сработает через несколько секунд. Он работает асинхронно и совсем не задерживает процесс создания пользователя. Таким образом, вам нужно будет как-то дождаться завершения функции, прежде чем вызывать user.getIdToken(refresh: true).

Это именно то, о чем я говорю в этом сообщении в блоге . Предлагаемое мной решение состоит в следующем:

  1. Клиент: создает пользователя
  2. Клиент: ожидает создания документа с UID пользователя в Firestore
  3. Server : Функция Auth onCreate вызывает
  4. Сервер: функция выполняет свою работу
  5. Сервер: В конце функция записывает данные в новый документ с UID нового пользователя
  6. Клиент: База данных Слушатель запускает создание документа

Затем вы добавили бы еще один шаг на клиенте, чтобы обновить sh маркер идентификатора после того, как он увидит новый документ.

Код, указанный в посте, предназначен для веб / javascript, но процесс применим к любому клиенту. Вам просто нужно заставить клиента ждать завершения функции, и Firestore - это удобное место для передачи этой информации, поскольку клиент может прослушивать ее в режиме реального времени.

Также читать этот пост способ заставить клиента немедленно обновить sh его токен на основе утверждений, записанных в документе Firestore.

Суть в том, что у вас достаточно кода для синхронизации c между клиентом и сервером.

2 голосов
/ 18 марта 2020

Для дальнейшего использования, мне удалось заставить это работать с предложениями Дуга.

Вот моя админская функция firebase sdk.

const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();

const firestore = admin.firestore();
const settings = {timestampsInSnapshots: true};
firestore.settings(settings);


// On sign up.
exports.processSignUp = functions.auth.user().onCreate(async user => {

// Check if user meets role criteria:
// Your custom logic here: to decide what roles and other `x-hasura-*` should the user get
let customClaims;
// Set custom user claims on this newly created user.

return admin.auth().setCustomUserClaims(user.uid, {
    'https://hasura.io/jwt/claims': {
    'x-hasura-default-role': 'user',
    'x-hasura-allowed-roles': ['user'],
    'x-hasura-user-id': user.uid
}
  })
.then(async () => {
    await firestore.collection('users').doc(user.uid).set({
        createdAt: admin.firestore.FieldValue.serverTimestamp()
    });
 })
 .catch(error => {
    console.log(error);
 });
});

Тогда на стороне флаттера

Future<FirebaseUser> signUp({String email, String password}) async {
    final FirebaseUser user = (await auth.createUserWithEmailAndPassword(
      email: email,
      password: password,
    )).user;
    currentUser = user;

    await waitForCustomClaims();
    return user;
}

Future waitForCustomClaims() async {
    DocumentReference userDocRef = 
    Firestore.instance.collection('users').document(currentUser.uid);
    Stream<DocumentSnapshot> docs = userDocRef.snapshots(includeMetadataChanges: false);

    DocumentSnapshot data = await docs.firstWhere((DocumentSnapshot snapshot) => snapshot?.data !=null && snapshot.data.containsKey('createdAt'));  
    print('data ${data.toString()}');

    IdTokenResult idTokenResult = await (currentUser.getIdToken(refresh: true));
    print('claims : ${idTokenResult.claims}');
}

Надеюсь, это поможет кому-то, кто хочет сделать подобное.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...