Express middleware: permite accesul la numai admin sau moderator

voturi
0

Vreau o rută să fie accesibilă numai de către moderator sau admin. Am încercat să aplice un middleware de matrice pe ruta. Dar, neagă doar accesul în cazul în care un middleware nu reușește să se aplice.
așa că, spun eu sunt admin sau un moderator mi pot accesa la /store-detail.
Dar aici, Dacă eu sunt admin eu nu pot avea acces , deoarece pentru a verifica moderator, de asemenea.
Aici _both middleware -uri adminși moderatorse aplică.
Vreau să aplice adminsau moderator.
Cum pot face doar una dintre ele să fie aplicate?
Așa că numai admin sau un moderator se poate accesa.
verifymiddleware este de a verifica jeton JWT.
router

router.post('/store-detail', [verify, admin, moderator], async (req, res) => {
    //validate data
}}

middleware

const User = require('../models').User

module.exports = async function (req, res, next) { 
    // 401 Unauthorized
    const user = await User.findOne({ where: { id : req.user.id}})
    if(user.role !== 'moderator') return res.status(403).send({error: { status:403, message:'Access denied.'}});
    next();
  }
const User = require('../models').User

module.exports = async function (req, res, next) { 
    // 401 Unauthorized
    const user = await User.findOne({ where: { id : req.user.id}})
    if(user.role !== 'admin') return res.status(403).send({error: { status:403, message:'Access denied.'}});
    next();
  }
Întrebat 09/10/2019 la 12:52
sursa de către utilizator
În alte limbi...                            


4 răspunsuri

voturi
1

Sunt executate succesiv, middleware-uri, astfel încât primul middleware care neagă accesul, trimite o eroare. Vă sugerez pentru a crea un singur middleware care acceptă un parametru:

module.exports = function hasRole(roles) {
  return async function(req, res, next) {
    const user = await User.findOne({ where: { id: req.user.id } });
    if (!user || !roles.includes(user.role) {
      return res.status(403).send({error: { status:403, message:'Access denied.'}});
    }
    next();
  }
}

Și de a folosi middleware ca aceasta:

router.post('/store-detail', verify, hasRole(['admin', 'moderator']), async (req, res) => {})
Publicat 09/10/2019 la 13:09
sursa de către utilizator

voturi
0

O soluție bazată pe JWT: (Ne pare rău pentru post lung, în cazul în care acest lucru este necorespunzatoare, eu pot șterge)

rută utilizatori (rute / users.js) Aici mă întorc o auth-token în funcțiune de conectare.

const auth = require("../middleware/auth");
const hasRole = require("../middleware/hasRole");
const bcrypt = require("bcryptjs");
const { User } = require("../models/user");
const express = require("express");
const router = express.Router();

router.post("/register", async (req, res) => {
  const { name, email, password } = req.body;

  let user = await User.findOne({ email });
  if (user) return res.status(400).send("User already registered.");

  user = new User({ name, email, password });
  const salt = await bcrypt.genSalt(10);
  user.password = await bcrypt.hash(user.password, salt);
  await user.save();

  const token = user.generateAuthToken();
  res.header("auth-token", token).send({ name, email });
});

router.post("/login", async (req, res) => {
  const { email, password } = req.body;

  let user = await User.findOne({ email });

  if (!user) return res.status(400).send("Invalid email or password.");

  const validPassword = await bcrypt.compare(password, user.password);

  if (!validPassword) return res.status(400).send("Invalid email or password.");

  const token = user.generateAuthToken();

  res.send(token);
});

module.exports = router;

user.js (User model) Aici am adăuga informații rol la JWT când semnarea:

const jwt = require("jsonwebtoken");
const mongoose = require("mongoose");

const userSchema = new mongoose.Schema({
  name: {
    type: String,
    required: true
  },
  email: {
    type: String,
    required: true,
    unique: true
  },
  password: {
    type: String,
    required: true
  },
  role: {
    type: String,
    default: "user"
  }
});

userSchema.methods.generateAuthToken = function() {
  const token = jwt.sign(
    { _id: this._id, role: this.role },
    process.env.JWT_PRIVATE_KEY
  );
  return token;
};

const User = mongoose.model("User", userSchema);

exports.User = User;

middleware / auth.js Aici autentifica utilizatorul, și adăugarea decodat jeton la cererea astfel încât să putem folosi în următoarele middleware-uri.

const jwt = require("jsonwebtoken");

module.exports = function(req, res, next) {
  const token = req.header("auth-token");
  if (!token) return res.status(401).send("Access denied. No token provided.");

  try {
    const decoded = jwt.verify(token, process.env.JWT_PRIVATE_KEY);
    req.user = decoded;
    next();
  } catch (ex) {
    res.status(400).send("Invalid token.");
  }
};

middleware / hasRole.js Aici vom verifica dacă user.role îndeplinește rolurile necesare.

module.exports = function hasRole(roles) {
  return function(req, res, next) {
    if (!req.user.role || !roles.includes(req.user.role)) {
      return res.status(403).send("Access denied.");
    }

    next();
  };
};


În cele din urmă vom adăuga următoarea cale pe ruta utilizatorii să poată testa rol de autorizare.

router.get("/me", [auth, hasRole(["admin", "moderator"])], async (req, res) => {
  const user = await User.findById(req.user._id).select("-password");
  res.send(user);
});

A testa:

Crearea 3 utilizatori separat cu următorul text cu POST următoarea adresă URL

http: // localhost: 3000 / api / utilizatori / registru

{
    "name": "admin",
    "email": "admin@so.com",
    "password" : "123456"
}

{
    "name": "moderator",
    "email": "moderator@so.com",
    "password" : "123456"
}

{
    "name": "user",
    "email": "user@so.com",
    "password" : "123456"
}

În MongoDB, în colecția utilizatorilor actualizăm proprietate rol de administrator pentru utilizator admin si moderator pentru utilizator moderator.

Folosind poștaș sau un instrument similar ne logam cu datele de autentificare admin sau un moderator.

În răspunsul, vom obține indicativul de autentificare, vom folosi în antet indicativului de autentificare pentru acest punct final protejat în cererea GET.

http: // localhost: 3000 / api / utilizatori / mi

Vei primi codul de stare 200.

De data aceasta ne logam cu datele de autentificare normale de utilizator. În răspunsul, vom copia indicativul de autentificare, și să-l utilizați în antetul-indicativului de autentificare pentru acest punct final protejat în cererea GET.

http: // localhost: 3000 / api / utilizatori / mi

Veți primi un cod de stare 403 Forbidden.

Publicat 09/10/2019 la 14:04
sursa de către utilizator

voturi
0

parte inoperant

Din punctul de vedere al arhitecturii sistemului, aici este ceea ce voi face.

  1. In loc de a face cerere de rețea în interiorul Everytime middleware, stoca nivelul de acces de utilizator într-un jeton (să zicem JWT jeton).

  2. Datele de conectare utilizator momentul în sistem, să facă o cerere la backend, backend va face cerere db la retrive detaliile (care ar trebui să ia în considerare nivelul de acces) și criptați detaliile utilizatorului în jeton. Indicativul dvs. ar trebui să conțină nivelul de acces.

  3. La fiecare cerere, veți avea jeton în antetele,-de criptă token-ul, și a stabilit detaliile nivelurilor de acces (res.locals ar trebui să fie locul ideal pentru a seta token-uri).

   const verifyUser = async (req, res, next) => {
        const token = req.cookies.userId
        if(token) {
          try {
            const tokenVerficiation = await verifyToken(token)
            res.locals.userId = tokenVerficiation.userId
            next()
          } catch (error) {
            return res.status(401).send(`Invalid Access token`)
          }
        } else { 
         return res.status(401).send(`Not Authorized to view this.`)
        }
    }

partea relevantă

Din moment ce setarea res.status(403).send({error: { status:403, message:'Access denied.'}});are sens de ce nu va trece la următorul middleware.

Din moment ce un Api suna puteți *Probablytrimite antete o dată După cum sa sugerat de către Jérémie L crearea unui singur middleware nou ar fi cea mai bună abordare

module.exports = function hasRole(roles) {
  return async function(req, res, next) {
    const user = await User.findOne({ where: { id: req.user.id } });
    if (!user || !roles.includes(user.role) {
      return res.status(403).send({error: { status:403, message:'Access denied.'}});
    }
    next();
  }
}
Publicat 09/10/2019 la 13:59
sursa de către utilizator

voturi
0

Creați o funcție nouă de exemplu , isAuthorizedsă se ocupe de această logică.

Dacă apelați [verify, admin, moderator]separat , ele nu sunt depindeau unul de altul.

traseu:

router.post('/store-detail', isAuthorized, async (req, res) => {
    //validate data
}}

function isAuthorized(req, res, next) {
  if (!verify(req)) 
    return next();
  if (!admin(req) && !moderator(req)) 
    return res.status(403).send({error: { status:403, message:'Access denied.'}});
}

middleware:

const User = require('../models').User

module.exports = async function (req, res, next) { 
  // 401 Unauthorized
  const user = await User.findOne({ where: { id : req.user.id}})
  if(user.role === 'moderator') 
    return true;
  return false;
}

Cred că trebuie să modificați verify(req), admin(req)și moderator(req).

Publicat 09/10/2019 la 13:06
sursa de către utilizator

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more