This post is also available in: English Español

Ao criar uma API, há momentos em que você não quer que sua API seja acessível publicamente para todos. Quer se trate de ter um nome de utilizador e uma palavra-passe simples ou de um cheque que confirme se alguém é um cliente pago, necessitará de uma forma de proteger as suas rotas contra utilizadores que não estão autenticados. Uma das melhores maneiras de fazer isso é usando JWT. JWT é um token sem estado que verifica com seu sistema back-end para validar suas solicitações de usuário.

Configuração do projeto

Supondo que você já tenha uma API no local, você desejará adicionar dependências para autenticação.

npm install –save passport passport-local passport-local-mongoose

Passport é uma ferramenta para autenticação Node.js aplicativos enquanto Passport-Local e Passport-Local-Mongoose ajudar a adicionar a capacidade de usar um nome de usuário simples e autenticação de senha. Passaporte-Local-Mongoose lida especificamente com o hashing de passaporte e sal em seu documento de usuário em Mongoose.

Agora que temos aqueles instalados, vamos caminhar para puxar em dependências para lidar com nossa criação JWT e autenticação com express.

npm install –save express-jwt jsonwebtoken passport-jwt

Passport-JWT adiciona middleware ao Passport para permitir que ele aceite tokens da web JSON como um tipo de autenticação válido. Agora que temos todas as nossas dependências puxadas para dentro, vamos adicionar Passport ao nosso aplicativo.

Primeiro, precisamos criar um modelo de usuário para representar nosso usuário armazenado e credencial em nosso banco de dados.

import mongoose from 'mongoose';
const Schema = mongoose.Schema;
import passportLocalMongoose from  'passport-local-mongoose';


let userSchema = new Schema({
    firstName: String,
    lastName: String,
    email: String,
    password: String
});

userSchema.plugin(passportLocalMongoose);

let User = mongoose.model('User',userSchema);

export default User;

Como você pode ver, adicionamos nosso e-mail e passaporte ao modelo, e logo abaixo dele, nós burro o plugin passaporte-local-mangusto para lidar com nosso hashing de senha. Mesmo que isso possa ser manuseado manualmente, você deve seguir os princípios de DRY. Se houver um pacote para lidar com uma tarefa comum, não reinvente a roda.

Agora que temos nosso modelo de usuário criado, agora podemos adicionar isso ao nosso pipeline de passaporte e configurar o passaporte para se conectar com o Express.

Adicione essas duas instruções de importação ao arquivo server.js (ou app.js)

import passport from 'passport';
import User from './models/user';

Em seguida, escolha o método de autenticação e configuração JWT que deseja usar.

const passportJWT = require("passport-jwt");
const JWTStrategy   = passportJWT.Strategy;
const ExtractJWT = passportJWT.ExtractJwt;

const LocalStrategy = require('passport-local').Strategy;
server.use(passport.initialize());
passport.use(new LocalStrategy({
        usernameField: 'email',
        passwordField: 'password'
    },
    User.authenticate()
));
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
passport.use(new JWTStrategy({
        jwtFromRequest: ExtractJWT.fromAuthHeaderAsBearerToken(),
        secretOrKey   : 'ILovePokemon'
    },
    function (jwtPayload, cb) {

        //find the user in db if needed. This functionality may be omitted if you store everything you'll need in JWT payload.
        return User.findById(jwtPayload.id)
            .then(user => {
                return cb(null, user);
            })
            .catch(err => {
                return cb(err);
            });
    }
));

Como você pode ver aqui, inicializamos uma instância do Passport, definimos a estratégia como local e, em seguida, definimos os campos que desejamos usar, bem como o modelo do usuário. A estratégia local significa apenas usar nome de usuário e senha.

Logo depois disso, dizemos ao passaporte como planejamos serializar e desserializar nosso usuário, e como configurar nosso JWT com nossa estratégia JWT. ExtractJWT.fromauthHeaderasBearerToken (), especifica que tokens JWT serão enviados como tokens Bearer em solicitações HTTP recebidas e que nossa chave secreta para criptografar nossos tokens é armazenada em SecretorKey.

Configurando Login de Usuário e Autenticação JWT

Como configuramos o Passport, vamos querer criar controladores lidar com nossos registros de usuários e nosso login que retorna um JWT válido.

Crie um controlador chamado auth.controller.js e importe o seguinte.

import User from '../models/user';
import bodyParser from 'body-parser';

import passport from 'passport';
const AuthController = {};
import jwt from 'jsonwebtoken';

Nós importamos Passport, nosso modelo, bem como jsonwebtoken como um método de assinar nossos tokens.

Também criamos um objeto chamado AuthController para exportar posteriormente para outros arquivos.

Agora que isso é feito, crie a função para registrar o usuário.

AuthController.register = async (req, res) => {
    try{
        User.register(new User({ username: req.body.email,
            firstName: req.body.firstName,
            lastName: req.body.lastName,
            }), req.body.password, function(err, account) {
            if (err) {
                return res.status(500).send('An error occurred: ' + err);
            }

            passport.authenticate(
                'local', {
                    session: false
                })(req, res, () => {
                res.status(200).send('Successfully created new account');
            });
        });
    }
    catch(err){
        return res.status(500).send('An error occurred: ' + err);
    }
};

O método user.register () usa um novo modelo de usuário, a senha e a mãe de autenticação como parâmetros.

Agora crie o método para fazer login

AuthController.login = async (req, res, next) => {
    try {
        if (!req.body.email || !req.body.password) {
            return res.status(400).json({
                message: 'Something is not right with your input'
            });
        }
        passport.authenticate('local', {session: false}, (err, user, info) => {
            if (err || !user) {
                return res.status(400).json({
                    message: 'Something is not right',
                    user   : user
                });
            }
            req.login(user, {session: false}, (err) => {
                if (err) {
                    res.send(err);
                }
                // generate a signed son web token with the contents of user object and return it in the response
                const token = jwt.sign({ id: user.id, email: user.username}, 'ILovePokemon');
                return res.json({user: user.username, token});
            });
        })(req, res);
    }
    catch(err){
        console.log(err);
    }
};

Isso verifica se os campos de email e senha não estão vazios. Isso está usando a autenticação local de passaporte para verificar se é um usuário válido. Em seguida, ele assina um token usando que os usuários informações e retorna esse token como json.

Proteger rotas

Agora que temos os métodos de autenticação criados, vamos ter que criar rotas para eles.

Criar os dois arquivos auth.routes.js e user.routes.js

import { Router } from 'express';
import AuthController from '../controllers/auth.controller';

const router = new Router();

router.post('/register', (req, res) => {
    AuthController.register(req, res);
});

router.post('/login', (req, res, next) => {
    AuthController.login(req, res, next);
});

export default router;

Aqui você pode ver que importamos Express e obter o roteador para exportar mais tarde. Também criamos rotas Post para o nosso AuthController.

Em nosso arquivo user.routes.js

import { Router } from 'express';
const router = new Router();

/* GET users listing. */
router.get('/', function(req, res, next) {
    res.send('respond with a resource');
});

/* GET user profile. */
router.get('/profile', function(req, res, next) {
    res.send(req.user);
});

export default router;

Isso retorna o usuário que fez a solicitação.

Agora, se voltarmos ao nosso arquivo server.js podemos adicionar esses arquivos de rota ao nosso pipeline expresso

import user from './routes/user.routes';import auth from './routes/auth.routes';

server.use('/auth', auth);server.use('/user', passport.authenticate('jwt', {session: false}), user);

Aqui passamos no Passport como nosso método de autenticação. O usuário deve agora ter um token JWT em todos os cabeçalhos para fazer solicitações para esse controlador.

User Creation
User Creation
User Login
User Login
JWT user profile
JWT user profile

Conclusão

Além de ter um token JWT no cabeçalho, você também pode usar isso como um método de criação de documentos MongoDB relacionados a um usuário. Um exemplo disso é ter um ID de usuário autenticado associado a uma publicação ou comentário na criação. Confira o repositório do GitHub para obter o código-fonte completo deste tutorial.

Codebrains Newsletter

Get weekly dev news and tutorials.

Powered by ConvertKit

This post is also available in: English Español