Поскольку я не могу воспроизвести вашу среду, я не могу гарантировать, что это 100% рабочий код, однако я проверил, что большинство функций работает должным образом.
Проверка запроса
Два набора условных выражений могут быть сведены вместе.Проверка правильности запроса и извлечение токена может быть выражена следующим образом: (Мы рассмотрим несанкционированный случай позже)
const token = hasToken(req) ? getToken(req) : false;
hasToken
проверит, еслизапрос req
имеет действительный заголовок авторизации или файл cookie __session
:
const hasBearer = pipe(pathOr('', ['headers', 'authorization']), startsWith('Bearer'));
const hasSession = hasPath(['cookies', '__session']);
const hasToken = either(hasBearer, hasSession);
Получение токена
Мы можем получить токен иззаголовок или из файла cookie:
const getBearer = pipe(path(['headers', 'authorization']), replace('Bearer ', ''));
const getSession = path(['cookies', '__session']);
const getToken = either(getBearer, getSession);
Создание 403 «несанкционированного» ответа
Мы могли бы также создать функцию для этого.Это может быть так просто:
const unauthorized = res => res.status(403).send('Unauthorized');
Но мы также можем разбить это на более мелкие многократно используемые фрагменты:
const status = invoker(1, 'status');
const send = invoker(1, 'send');
const unauthorized = pipe(status(403), send('Unauthorized'));
Так что если вы хотите генерировать ответы другого типа, вымог бы сделать:
const notFound = pipe(status(404), send('Not Found'));
const serverError = pipe(status(500), send('Server Error'));
Проверка правильности токена
Мы можем использовать функциональный подход для попытки / перехвата:
const verifyToken = async (admin, token) =>
tryCatch(() => admin.auth().verifyIdToken(token), F)();
Возвращение контроля admin
Оригинальная функция validateFirebaseIdToken
использует внешнюю переменную admin
, что не идеально для ИМХО.Было бы лучше, чтобы он был передан в качестве параметра.Для этого мы можем использовать curry
:
const validateFirebaseIdTokenFunction = curry(async (admin, req, res, next) => {
// …
});
Собираем все вместе
const {
curry,
either,
F,
hasPath,
invoker,
path,
pathOr,
pipe,
replace,
set,
startsWith,
tryCatch } = require('ramda');
const hasBearer = pipe(pathOr('', ['headers', 'authorization']), startsWith('Bearer'));
const getBearer = pipe(path(['headers', 'authorization']), replace('Bearer ', ''));
const hasSession = hasPath(['cookies', '__session']);
const getSession = path(['cookies', '__session']);
const hasToken = either(hasBearer, hasSession);
const getToken = either(getBearer, getSession);
const status = invoker(1, 'status');
const send = invoker(1, 'send');
const unauthorized = pipe(status(403), send('Unauthorized'));
const verifyToken = async (admin, token) =>
tryCatch(() => admin.auth().verifyIdToken(token), F)();
const validateFirebaseIdTokenFunction = curry(async (admin, req, res, next) => {
const token = hasToken(req) ? getToken(req) : false;
const tokenVerified = token ? await verifyToken(admin, token) : false;
return tokenVerified ? set('user', tokenVerified, req) && next() : unauthorized(res);
});
// This function now “waits” for the remaining arguments: `req`, `res` and `next`
const validateFirebaseIdToken = validateFirebaseIdTokenFunction(admin);
Список используемых функций Ramda