Автор оригинала: Victor Nwaiwu.
Это обновленная версия этого поста, которую я сделал в 2017 году. И с тех пор Firebase претерпела много изменений и пересмотра. Это работает по состоянию на 2019 год, и вы должны быть хороши, чтобы пойти. Вы должны слышать о простоте Firebase и как она заходит как все в одном решении для управления базами данных, аутентификации и хранения. Знаете ли вы, что вы можете использовать FireBase в качестве промежуточного программного обеспечения аутентификации, и вам больше не нужно будет хранить сеансы в вашей базе данных? Сегодня я буду говорить о написании промежуточного программного обеспечения для вашего экспресс-приложения, используя только FireBase-admin. Вот шаги, необходимые для создания промежуточного программного обеспечения с FireBase. Создайте учетную запись в Google: если у вас нет учетной записи в Google, вы можете создать один здесь. После создания учетной записи отправляйтесь на консоль Google Firebase и создайте учетную запись, если у вас нет одного. После создания учетной записи вам нужно будет создать проект в Firebase. Создание проекта даст вам объект конфигурации, который позволяет подключать приложение к базе данных FireBase, хранилище и аутентификации. Firebase предоставляет вам учетную запись услуг, которая позволяет использовать Admin-admin FireBase в вашей бэкэнде.
Установите FireBase-admin в узле: Установите FireBase-admin в приложении узла, запустив NPM Установите Firebase-admin – Сохранить. Это сохранит Admin FireBase в зависимостях приложений в случае, если вы хотите запустить его в другой среде. Создание объекта Config FireBase: создайте файл конфигурации FireBase, который инициализирует ваш объект FireBase-Admin, который будет использоваться в приложении. Это класс Singleton.
{ "type": "service_account", "project_id": "", "private_key_id": " ", "private_key": " ", "client_email": " ", "client_id": " ", "auth_uri": "https://accounts.google.com/o/oauth2/auth", "token_uri": "https://oauth2.googleapis.com/token", "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/ .iam.gserviceaccount.com" }
Инициализируйте FireBase для вашего приложения: после создания объекта Config и требуя FireBase и его служб (база данных и аутентификации), вам нужно будет инициализировать FireBase в вашем приложении, например:
require('dotenv').config(); import firebase from 'firebase-admin'; var serviceAccount = require('./firebase-service-account.json'); export default firebase.initializeApp({ credential: firebase.credential.cert(serviceAccount), databaseURL: process.env.FIREBASE_DATABASE_URL })
Создайте контроллер для аутентификации пользователей на бэкэнде, используя инициализированный файл конфигурации FireBase. Это предполагает, что вы уже обрабатывали аутентификации пользователей в вашем клиентском приложении. Вы можете проверить документы для аутентификации пользователей.
// import the firebase config into the auth controller import firebase from '../../firebase'; const firebaseAuth = async (req, res) => { try { // req.body the payload coming from the client to authenticate the user // uid is the firebase uid generated when a user is authenticated on the firebase client const userRequest = await firebase.database().ref(`users/${req.body.uid}`).once('value'); const userPayload = userRequest.val(); if (userPayload) { // create tokenClaims if you wish to add extra data to the generated user token const tokenClaims = { roleId: userPayload.roleId } // use firebase admin auth to set token claimsm which will be decoded for additional authentication await firebase.auth().setCustomUserClaims(user.uid, tokenClaims); return res.status(200).json({data: tokenClaims}); } else { return res.status(404).json({error: {message: 'No user found'}}); } } catch (error) { return res.status(500).json({ error: { message: 'could not complete auth request'} }); } } export default { firebaseAuth }
Создайте промежуточное программное обеспечение, которое проверяет токен FireBase, отправленный из заголовка запроса, как так
// Import Firebase Admin initialized instance to middleware import firebase from '../../firebase'; const roleRanks = { superAdmin: 1, admin: 2, user: 3 }; export const decodeFirebaseIdToken = async (req, res, next) => { if (!req.headers.id_token) { return res.status(400).json({ error: { message: 'You did not specify any idToken for this request' } }); } try { // Use firebase-admin auth to verify the token passed in from the client header. // This is token is generated from the firebase client // Decoding this token returns the userpayload and all the other token claims you added while creating the custom token const userPayload = await firebase.auth().verifyIdToken(req.headers.id_token); req.user = userPayload; next(); } catch (error) { return res.status(500).json({ error }); } }; // Checks if a user is authenticated from firebase admin export const isAuthorized = async (req, res, next) => { if (req.user) { next(); } else { return res.status(401).json({ error: { message: 'You are not authorised to perform this action. SignUp/Login to continue' } }); } }; // Checks if a user has the required permission from token claims stored in firebase admin for the user export const hasAdminRole = async (req, res, next) => { try { const roleRequest = await firebase.database().ref('roles').once('value'); const rolesPayload = roleRequest.val(); const role = rolesPayload.find((role) => role.id === roleRanks.admin) if (req.user.roleId <= role.id) { next(); } else { return res.status(403).json({ error: { message: 'You are not permitted to access this resource' } }); } } catch(error) { return res.status(500).json({ error: { message: 'An error occurred while getting user access. Please try again' } }); } };
Используйте промежуточное программное обеспечение в маршруте: Наконец, после создания промежуточного программного обеспечения вы можете использовать это промежуточное программное обеспечение в маршруте и увидеть, что он работает так:
import { hasAdminRole, decodeFirebaseIdToken, isAuthorized } from '../controllers/middleware/auth.middleware'; const UserRoute = (router) => { // Get all users router.route('/users') .get( decodeFirebaseIdToken, isAuthorized, hasAdminRole, UserController.getAllUsers ) } export default UserRoute;
Вот как все это происходит вместе в файле точек входа для вашего экспресс-приложения:
import express from 'express'; import path from 'path'; import bodyParser from 'body-parser'; import routes from './routes'; import cors from 'cors'; const app = express(); const router = express.Router(); const headers1 = 'Origin, X-Requested-With, Content-Type, Accept'; const headers2 = 'Authorization, Access-Control-Allow-Credentials, x-access-token'; const whitelist = [process.env.CLIENT_URL]; const corsOptionsDelegate = (req, callback) => { let corsOptions; if (whitelist.indexOf(req.header('Origin')) !== -1) { corsOptions = { origin: true }; } else if (process.env.NODE_ENV === 'production') { corsOptions = { origin: true }; } else { corsOptions = { origin: false }; } callback(null, corsOptions); }; // setup body parser app.use(bodyParser.urlencoded({ extended: true })); app.use(bodyParser.json()); // Use express backend routes routes(router); const clientHeaderOrigin = process.env.CLIENT_URL; app.use(cors(corsOptionsDelegate)); app.use((req, res, next) => { const origin = req.headers.origin; if(whitelist.indexOf(origin) > -1){ res.header('Access-Control-Allow-Origin', origin); } else { res.header('Access-Control-Allow-Origin', clientHeaderOrigin); } res.header('Access-Control-Allow-Methods', 'GET, POST, DELETE, PATCH, OPTIONS, PUT'); res.header('Access-Control-Allow-Headers', `${headers1},${headers2}`); res.header('Access-Control-Allow-Credentials', 'true'); next(); }); // Add API Routes app.use('/api', router); const port = process.env.PORT || 3000; // start the app by using heroku port app.listen(port, () => { console.log('App started on port: ' + port); });
Вам не нужно использовать другой пакет в качестве аутентификационного промежуточного программного обеспечения и хранилищ сеансов в вашей базе данных. Не забудьте задать мне любой вопрос или если есть какая-то часть, которую вы не понимаете.