Аутентификация Firebase против AWS Cognito

Мы создаем мобильное и веб-приложение на AWS с использованием API Gateway и Lambda и в настоящее время оцениваем, следует ли использовать все мобильные сервисы AWS (Cognito, Analytics, Mobile Hub и т.д.) или использовать вместо этого Firebase предлагает некоторые преимущества, такие как удаленная конфигурация).

Я думаю, что использование безфункционной части firebase, такой как Analytics, Remote Config, Crash Reports, Notification должно быть хорошо с бэкэндом AWS. Часть была я не уверен, это уровень аутентификации.

AWS Cognito прекрасно интегрируется в API Gateway и Lamdba, например. только аутентифицированные пользователи могут выполнять определенные вызовы API.

Может ли такое же поведение быть достигнуто, если мы будем использовать Firebase Authentication вместо этого? Любой хороший или плохой опыт с этим?

Ответ 1

мы делаем то же самое. Мы начали с Cognito, но перешли в Firebase, потому что нас не устраивало то, как AWS Android SDK реализует поток аутентификации с Google и Facebook: код довольно старый, он использует устаревшие методы и обычно требует перезаписи. С другой стороны, аутентификация Firebase, очевидно, работает без проблем. Когда вы не используете Cognito, вам необходимо реализовать свой собственный аутентификатор в AWS API Gateway, который довольно прост и описан в https://aws.amazon.com/blogs/mobile/integrating-amazon-cognito-user-pools-with-api-gateway/. Инструкции Firebase для проверки токена находятся в https://firebase.google.com/docs/auth/admin/verify-id-tokens

Ниже приведен фрагмент моего кода аутентификации:

'use strict';

// Firebase initialization
// console.log('Loading function');
const admin = require("firebase-admin");
admin.initializeApp({
  credential: admin.credential.cert("xxx.json"),
  databaseURL: "https://xxx.firebaseio.com"
});
// Standard AWS AuthPolicy - don't touch !!
...
// END Standard AWS AuthPolicy - don't touch !!

exports.handler = (event, context, callback) => {
    // console.log('Client token:', event.authorizationToken);
    // console.log('Method ARN:', event.methodArn);

    // validate the incoming token
    // and produce the principal user identifier associated with the token

    // this is accomplished by Firebase Admin
    admin.auth().verifyIdToken(event.authorizationToken)
        .then(function(decodedToken) {
            let principalId = decodedToken.uid;
            // console.log(JSON.stringify(decodedToken));

            // if the token is valid, a policy must be generated which will allow or deny access to the client

            // if access is denied, the client will recieve a 403 Access Denied response
            // if access is allowed, API Gateway will proceed with the backend integration configured on the method that was called

            // build apiOptions for the AuthPolicy
            const apiOptions = {};
            const tmp = event.methodArn.split(':');
            const apiGatewayArnTmp = tmp[5].split('/');
            const awsAccountId = tmp[4];
            apiOptions.region = tmp[3];
            apiOptions.restApiId = apiGatewayArnTmp[0];
            apiOptions.stage = apiGatewayArnTmp[1];

            const method = apiGatewayArnTmp[2];
            let resource = '/'; // root resource
            if (apiGatewayArnTmp[3]) {
                resource += apiGatewayArnTmp[3];
            }


            // this function must generate a policy that is associated with the recognized principal user identifier.
            // depending on your use case, you might store policies in a DB, or generate them on the fly

            // keep in mind, the policy is cached for 5 minutes by default (TTL is configurable in the authorizer)
            // and will apply to subsequent calls to any method/resource in the RestApi
            // made with the same token

            // the policy below grants access to all resources in the RestApi
            const policy = new AuthPolicy(principalId, awsAccountId, apiOptions);
            policy.allowAllMethods();
            // policy.denyAllMethods();
            // policy.allowMethod(AuthPolicy.HttpVerb.GET, "/users/username");

            // finally, build the policy and exit the function
            callback(null, policy.build());
            })
        .catch(function(error) {
            // Firebase throws an error when the token is not valid
            // you can send a 401 Unauthorized response to the client by failing like so:
            console.error(error);
            callback("Unauthorized");
        });
};

Мы пока не работаем, но тесты на аутентификаторе показывают, что он корректно ведет себя с проверкой подлинности Google, Facebook и пароля, а также очень быстро (60 - 200 мс). Единственный недостаток, который я вижу, - это то, что вы будете платить за функцию лямбда-аутентификатора, а встроенный аутентификатор Cognito свободен.

Ответ 2

TL; DR; Firebase > Cognito

Сначала мы начали с Cognito, но в итоге мы поняли, что у него есть ужасный запах, когда он приходит с использованием Federated Identities (например, вход в Google, вход в систему Facebook и т.д.). Для пулов пользователей Cognito (т.е. Позволяя пользователю регистрироваться/вводиться с именем пользователя и паролем), вы можете использовать встроенный авторизованный пул пользователей Cognito API Gateway, и он прекрасно работает. Вам не нужно писать свой собственный авторизатор или что-то еще.

Однако, если вы хотите поддерживать Federated Identities, вам нужно изменить аутентификацию на своем шлюзе API на IAM Auth, а затем пусть каждый клиент sigv4 подпишет запросы, которые оказались шипами на нашей стороне и стоили значительных время разработки. Вариант 2 заключался в том, чтобы API Gateway генерировал код для ваших вызовов API для каждого клиента... который, на мой взгляд, является свидетельством громоздкой интеграции с Cognito.

Мы получили Firebase, работающую через специальный авторизатор для API Gateway. Был бриз для всех клиентов (iOS, Android и Web). Конечные точки API-шлюза были связаны с функциями Lambda, которые могли взаимодействовать с DynamoDB, S3 и другими веб-службами от имени пользователя, вызывающего конечную точку. Лямбда-функции знали, кто был вызывающим пользователем, потому что пользовательский авторизатор вернул адрес электронной почты в JWT.

Вот довольно простой пользовательский авторизатор Firebase, который возвращает пользовательский адрес электронной почты в JWT как mainId:

'use strict';
console.log('Loading function');

var admin = require('firebase-admin');
var serviceAccount = require('./my-secret-json.json');

admin.initializeApp({
    credential: admin.credential.cert(serviceAccount),
    databaseURL: 'https://my-app.firebaseio.com'
});

exports.handler = (event, context, callback) => {
    var token = event.authorizationToken;

    if (token == null) {
        callback('Invalid token');
    }
    else {
        admin.auth().verifyIdToken(token)
            .then(function (decodedToken) {
                var email = decodedToken.email;
                var policy = generatePolicy(email);
                callback(null, policy);
            }).catch(function (error) {
                console.log(error);
                callback('Unauthorized'); 
            });
    }
};

var generatePolicy = function (email) {
    return {
        principalId: email,
        policyDocument: {
            Version: '2012-10-17',
            Statement: [
                {
                    Action: 'execute-api:Invoke',
                    Effect: email ? 'allow' : 'deny',
                    Resource: '*'
                }
            ]
        }
    };
}

Затем вы можете использовать $context.authorizer.principalId в шаблоне сопоставления шлюза API, чтобы получить электронное письмо и передать его лямбда X.

Ответ 3

Документация Aws довольно запутана. Система обратных вызовов для разных этапов аутентификации лучше документирована в Firebase. Результатом является более чистый код и лучший контроль потока аутентификации. Кроме того, пользовательский интерфейс Firebase более удобен для пользователя. Если вы планируете использовать контент-провайдеры и адаптеры синхронизации, я бы предложил использовать Firebase, потому что у вас будут простые методы синхронизации данных между локальной и удаленной (Firebase) db

Ответ 4

aws cognito предоставляет больше возможностей для аутентификации пользователей, чем firebase. Особенно, если вы строите игру, она дает возможность входа в игровые центры google и ios. Он обеспечивает синхронизацию лидеров и достижения игрового центра. Функция автоматической синхронизации состояния доступна в Cognito. Но определенно, это очень запутанно. Для реализации требуется слишком много времени. С другой стороны, проверка подлинности с помощью firebase довольно быстро реализуется.

Ответ 5

На всякий случай, если вы используете Unity, в настоящее время Unity SDK не поддерживает Cognito User Pool. (То есть, список пользователей, размещенных в AWS). В настоящее время я не согласен с этим. См. Мой пост здесь, что они подтвердили, что это правда, в настоящее время (26/06/2017) функция по-прежнему недоступна, что может показать отсутствие внимание пользователей Unity от них.

Однако, если я использую Firebase для входа в систему, мне понадобится дополнительная интеграция для этих учетных данных для использования служб AWS. (Я хотел бы использовать S3 и DynamoDB, но только пользователь в системе может использовать его.) Это также заставило меня понять, что я должен переместить все в Firebase, чтобы как можно скорее сохранить время и разочарования. (БД реального времени более дорогая, чем S3/DynamoDB, но Unity имеет собственную замену AWS MobileAnalytics)

Недавно AWS S3 получил более удобный интерфейс, который, как мне кажется, близок к уровню Google. Но кроме этого я думаю, что Firebase UI гораздо радостнее использовать.

Кроме того, аутентификация Firebase бесплатна, а Cognito бесплатна до 50 000 активных пользователей в месяц. (Следующие 50k будут стоить 0,0055, что означает, что если у вас есть 100k MAU, это будет 50000 * 0.0055 = 275 USD https://aws.amazon.com/cognito/pricing/)

Еще одна вещь, Документация AWS.NET - это кошмар для чтения/поиска по моему мнению.