Как обновить сессионный файл cookie Firebase - PullRequest
0 голосов
/ 07 октября 2018

Я разрабатываю веб-приложение, используя Node.js / Express.js для бэкэнда, и использую Firebase для аутентификации пользователя, управления регистрацией пользователя и т. Д. Я использую Firebase Admin SDK.

Когда пользовательЯ хочу войти в систему, используя его Firebase Client SDK следующим образом:

// Handling User SignIn
$('#signin').on('click', function(e){
    e.preventDefault();

    let form = $('#signin-form'),
        email = form.find('#email').val(),
        pass = form.find('#password').val(),
        errorWrapper = form.find('.error-wrapper');

    if(email && pass){
        firebase.auth().signInWithEmailAndPassword(email, pass)
            .catch(err => {
                showError(errorWrapper, err.code)
            });
    }else {
        showError(errorWrapper, 'auth/required');
    }
});

Ниже этого кода я назначаю наблюдателя, который будет наблюдать за успешным входом пользователя. После успешного входа я получаю FirebaseИдентификационный токен, который я отправляю конечной точке на сервере, чтобы обменять его на cookie-файл сеанса, который требует идентичный токен идентификатора, поскольку срок действия последнего истекает через 1 час.

// POST to session login endpoint.
let postIdTokenToSessionLogin = function(url, idToken, csrfToken) {
    return $.ajax({
        type: 'POST',
        url: url,
        data: {
            idToken: idToken,
            csrfToken: csrfToken
        },
        contentType: 'application/x-www-form-urlencoded'
    });
};

// Handling SignedIn Users 
firebase.auth().onAuthStateChanged(function(user) {
    if (user) {
        user.getIdToken().then(function(idToken) {
            let csrfToken = getCookie('csrfToken');
            return postIdTokenToSessionLogin('/auth/signin', idToken, csrfToken)
                .then(() => {
                        location.href = '/dashboard';
                    }).catch(err => {
                        location.href = '/signin';
                    });
                });
        });
    } else {
        // No user is signed in.
    }
});

Вход в конечную точку на сервере выполняет поискнапример:

// Session signin endpoint.
router.post('/auth/signin', (req, res) => {
    // Omitted Code...
    firebase.auth().verifyIdToken(idToken).then(decodedClaims => {
        return firebase.auth().createSessionCookie(idToken, {
            expiresIn
        });
    }).then(sessionCookie => {
        // Omitted Code...
        res.cookie('session', sessionCookie, options);
        res.end(JSON.stringify({
            status: 'success'
        }));
    }).catch(err => {
        res.status(401).send('UNAUTHORIZED REQUEST!');
    });
});

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

function isAuthenticated(auth) {
    return (req, res, next) => {
        let sessionCookie = req.cookies.session || '';
        firebase.auth().verifySessionCookie(sessionCookie, true).then(decodedClaims => {
            if (auth) {
                return res.redirect('/dashboard')
            } else {
                res.locals.user = decodedClaims;
                next();
            }
        }).catch(err => {
            if (auth) next();
            else return res.redirect('/signin')
        });
    }
}

Чтобы отобразить информацию пользователя наview Я устанавливаю декодированные заявки на переменную res.locals.user и передаю ее следующему промежуточному программному обеспечению, где я отображаю представление и передаю эту переменную следующим образом.

router.get('/', (req, res) => {
    res.render('dashboard/settings', {
        user: res.locals.user
    });
});

Пока все в порядке, теперь проблема возникает после того, как пользователь заходит на свою панель инструментов, чтобы изменить свою информацию (имя и адрес электронной почты), когда он отправляет форму с именем и адресом электронной почты конечной точке насервер Я обновляю его учетные данные, используя Firebase Admin SDK

// Handling User Profile Update
function settingsRouter(req, res) {
    // Validate User Information ...
    // Update User Info
    let displayName = req.body.fullName,
        email = req.body.email
    let userRecord = {
        email,
        displayName
    }
    return updateUser(res.locals.user.sub, userRecord).then(userRecord => {
        res.locals.user = userRecord;
        return res.render('dashboard/settings', {
            user: res.locals.user
        });
    }).catch(err => {
        return res.status(422).render('dashboard/settings', {
            user: res.locals.user
        });
    });
}

Теперь представление обновляется, когда пользователь отправляет форму, потому что я установил переменную res.locals.user в новое userRecord, но как только он обновил страницу,Представление показывает старые учетные данные, потому что перед любым запросом get для защищенного содержимого выполняется промежуточное программное обеспечение isAuthenticated, а последующее получает информацию о пользователе из cookie-файла сеанса, который содержит старые пользовательские учетные данные, прежде чем он обновил их.

ИтакПока это выводы, к которым я пришел и что я пытался сделать:

  • Если я хочу, чтобы представление правильно отображалось, я должен выйти и войти снова, чтобы получить новый идентификатор Firebase IDтокен для создания нового файла cookie сеанса, который не является опцией.

  • Я попытался обновитьcookie сеанса путем создания нового ID-токена из Admin SDK, но, похоже, эта опция недоступна, и я не могу сделать это через клиентский SDK, поскольку пользователь уже вошел в систему.

  • Сохранение идентификатора токена для использования в дальнейшем при создании файлов cookie сеанса не является вариантом, так как срок их действия истекает через 1 час.

Я, черт возьми, решил эту проблему, прежде чем опубликовать ее здесь, поэтомулюбая помощь очень ценится.

1 Ответ

0 голосов
/ 15 февраля 2019

У меня очень похожий сценарий с одним из моих приложений.Я думаю, что ответ заключается в этих подсказках.

Из Документы Firebase

Firebase Auth обеспечивает управление файлами cookie сеанса на стороне сервера для традиционных веб-сайтов, которые используют файлы cookie сеанса,Это решение имеет несколько преимуществ по сравнению с короткоживущими идентификационными токенами на стороне клиента, для которых может каждый раз потребоваться механизм перенаправления для обновления cookie сеанса по истечении срока действия:

Таким образом, они намекают здесь, что вы хотитеуправлять сеансом и временем его существования с сервера.

Второй ключ находится в документах

Предполагается, что приложение использует httpOnly серверные файлы cookie , войдите в систему на странице входа в систему с помощью клиентских SDK.Генерируется токен Firebase ID, а затем токен ID отправляется через HTTP POST в конечную точку входа в сеанс, где с помощью Admin SDK генерируется cookie сеанса.В случае успеха состояние должно быть очищено из хранилища на стороне клиента .

Если вы посмотрите на пример кода, даже явно установленное постоянство None, чтобы очистить состояние от клиентаиспользуя firebase.auth().setPersistence(firebase.auth.Auth.Persistence.NONE);

Таким образом, они намерены, чтобы на клиенте не было никакого состояния, кроме первоначальной аутентификации.Они явно очищают это состояние и ожидают файл cookie httponly, чтобы клиент не мог получить файл cookie (который на самом деле является просто токеном идентификатора) и использовать его для получения нового файла.

Странно, чтоНет ясного способа обновить токена на стороне клиента, но это так.Вы действительно можете создать только куки-файл сеанса с очень долгим сроком службы и решить на сервере, когда удалять куки-файл или отзывать маркер обновления и т. Д.

Так что остается другой вариант: управлять состоянием на стороне клиента.Некоторые примеры и учебные пособия просто отправляют идентификационный токен с клиента на сервер в виде файла cookie.Satte находится на клиенте, и клиент может использовать токен ID для использования всех функций Firebase.Сервер может проверить личность пользователя и использовать токен и т. Д.

Этот сценарий должен работать лучше.Если серверу нужно пнуть пользователя, он может удалить cookie, отозвать токен обновления (правда, немного резкий).

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

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