Как правильно организовать авторизацию веб-сервиса на Express?

Хочу использовать Express как веб сервис для моего Angular приложения. Как правильно организовать авторизацию? Как я понимаю стандартные сессии и куки не подойдут, или подойдут? Как на счет jwt? Если использовать jwt то как задать в req конкретного юзера?
  • Вопрос задан
  • 2786 просмотров
Пригласить эксперта
Ответы на вопрос 3
maxfarseer
@maxfarseer
https://maxpfrontend.ru, обучаю реакту и компании
Как на счет jwt ?

За! Удобно, нравится.

Вкратце - шлете стандартные регистрационные данные, сервер выдает вам токен. Далее токен добавляете в заголовки запросов.

В прицнипе, в гугле инфы хватает по вопросу. Сам сайт посмотрите (jwt.io), оттуда ссылка на пакет для node

Скопирую сюда куски кода из своего api сервера, но скажу сразу - в node я не очень силен, если будут замечания от знающих - только рад. Так же angular кода не приведу, потому что клиентский код у меня на react.

Здесь в файле используются callbacks, возможно есть варианты получше. В других роутах приложения я где-то через async поигрался, где-то через promise.

Мой роутер auth

const express = require('express')
const router = express.Router()
const User = require('../models/user')
const v4 = require('node-uuid').v4
const jwt = require('jsonwebtoken')

router.post('/signup', (req, res, next) => {

  req.check('email', 'Please enter a valid email').len(1).isEmail()
  req.check('password', 'Please enter a password with a length between 4 and 34 digits').len(4, 34)

  const errors = req.validationErrors()

  if (errors) {
    return res.status(400).json({ errors })
  } else {
    User.hashPassword(req.body.password, (err, passwordHash) => {
      if (err) {
        return res.status(400).json({ error: err.message })
      }

      const user = new User({
        name: req.body.name,
        nickname: req.body.nickname,
        email: req.body.email,
        password: req.body.password,
      })

      user.passwordHash = passwordHash
      user.save((err, item) => {
        if (err) {
          return res.status(400).json({ error: err.message })
        }
        const payload = {
          _id: item._id,
          iss: 'http://localhost:3000',
          permissions: 'poll',
        }
        const options = {
          expiresIn: '7d',
          jwtid: v4(),
        }
        const secret = new Buffer(process.env.AUTH0_CLIENT_SECRET, 'base64')
        jwt.sign(payload, secret, options, (err, token) => {
          return res.json({ data: token })
        })
      })
    })
  }
})

router.post('/signin', (req, res, next) => {

  req.check('email', 'Please enter a valid email').len(1).isEmail()
  req.check('password', 'Please enter a password with a length between 4 and 34 digits').len(4, 34)

  const errors = req.validationErrors()
  const password = req.body.password

  if (errors) {
    return res.status(400).json({ errors })
  } else {
    User.findOne({ email: req.body.email }, (err, user) => {
      if (err) {
        return res.status(400).json({ error: err.message })
      }
      if (!user) {
        return res.status(400).json({ error: 'User not found' })
      }
      User.comparePasswordAndHash(password, user.passwordHash, (err, areEqual) => {
        if (err) {
          return res.status(400).json({ error: err.message })
        }
        if (!areEqual) {
          return res.status(400).json({ error: 'Wrong password' })
        }
        const payload = {
          _id: user._id,
          iss: 'http://localhost:3000',
          permissions: 'poll',
        }
        const options = {
          expiresIn: '7d',
          jwtid: v4(),
        }
        const secret = new Buffer(process.env.AUTH0_CLIENT_SECRET, 'base64')
        jwt.sign(payload, secret, options, (err, token) => {
          return res.json({ data: token })
        })
      })
    })
  }
})

module.exports = router;


Модель user

const mongoose = require('mongoose')
const bcrypt = require('bcrypt')
const Schema = mongoose.Schema
let bcrypt_cost = 12

const userSchema = new Schema({
  name: { type: String, required: true },
  email: { type: String, required: true },
  passwordHash: String,
})

userSchema.statics.hashPassword = (passwordRaw, cb) => {
  if (process.env.NODE_ENV === 'test') {
    bcrypt_cost = 1
  }
  bcrypt.hash(passwordRaw, bcrypt_cost, cb)
}

userSchema.statics.comparePasswordAndHash = (password, passwordHash, cb) => {
  bcrypt.compare(password, passwordHash, cb)
}

const User = mongoose.model('User', userSchema)

module.exports = User


В коде роутера есть AUTHO_CLIENT - так как я изначально брал реализацию от AUTH0, кстати, может понравится? У них удобно все... Но для себя в целях обучения переписал на свою. (какая-то ссылка у них про angular cookies vs token)

Мне нравится, что некоторую информацию я могу взять прямо из токена (например, уровень доступа - в моем примере - poll)
Ответ написан
@LiguidCool
К express вроде как passport js прокручивается.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы
13 дек. 2019, в 10:53
1000 руб./за проект
13 дек. 2019, в 09:20
2500 руб./за проект