Uttrykke mellomvare: gi tilgang til bare admin eller moderator

stemmer
0

Jeg vil ha en rute til å være bare tilgjengelig med moderator eller admin. Jeg prøvde å bruke en mellomvare array på ruten. Men, det bare nekter tilgang hvis en mellomvare unnlater å søke.
så sier jeg er admin eller moderator jeg kan få tilgang til /store-detail.
Men her, hvis jeg er admin Jeg får ikke tilgang til det fordi det sjekk for moderator også.
Her _both middlewares adminog moderatorblir brukt.
Jeg vil at det skal gjelde admineller moderator.
Hvordan kan jeg gjøre bare en av dem til å bli brukt?
Slik at bare administrator eller moderator kan få tilgang til det.
verifymellomvare er å verifisere jwt token.
router

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

middlewares

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();
  }
Publisert på 09/10/2019 klokken 12:52
kilden bruker
På andre språk...                            


4 svar

stemmer
1

Middlewares utføres suksessivt, slik at den første mellomvare som nekter adgang, sender en feilmelding. Jeg foreslår å lage en enkelt mellomvare som aksepterer en parameter:

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();
  }
}

Og bruke mellomvare som dette:

router.post('/store-detail', verify, hasRole(['admin', 'moderator']), async (req, res) => {})
Svarte 09/10/2019 kl. 13:09
kilden bruker

stemmer
0

En JWT basert løsning: (beklager for det lange innlegget, hvis dette er unappropriate, kan jeg slette)

brukere rute (ruter / users.js) Her jeg kommer tilbake en auth-token i innloggings drift.

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 (Bruker Model) Her jeg legge rolle informasjon i JWT når du registrerer det:

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;

mellomvare / auth.js Her autentisere jeg bruker, og legge dekodet token til forespørselen, slik at vi kan bruke de neste middlewares.

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.");
  }
};

mellomvare / hasRole.js Her sjekker vi om user.role oppfyller de nødvendige rollene.

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();
  };
};


Til slutt vi legge til følgende banen til brukerne rute til å kunne teste rolle autorisasjon.

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

Å teste:

Lag 3 brukere separat med følgende med POST til følgende url

http: // localhost: 3000 / api / brukere / register

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

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

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

I mongodb i brukere samlingen oppdaterer vi rolle eiendom til admin for admin-bruker, og moderator for moderator bruker.

Ved hjelp av postmannen eller lignende verktøy vi Logg inn med admin eller moderator legitimasjon.

I svaret, får vi autoriseringstoken, bruker vi det i auth-token header for beskyttet endepunkt i GET forespørsel.

http: // localhost: 3000 / api / brukere / meg

Du vil få statuskode 200.

Denne gangen login vi med normal brukerlegitimasjon. I svaret, kopierer vi auth token, og bruke det i auth-token header for beskyttet endepunkt i GET forespørsel.

http: // localhost: 3000 / api / brukere / meg

Du vil få statuskode 403 Forbidden.

Svarte 09/10/2019 kl. 14:04
kilden bruker

stemmer
0

irrelevant del

Fra systemarkitektur synspunkt, her er hva jeg vil gjøre.

  1. I stedet for å lage nettverk forespørsel inne i mellomvare gang, lagre brukertilgang nivå i en token (si JWT token).

  2. I det øyeblikket bruker logikk i systemet, gjør en forespørsel til backend, vil backend gjøre forespørsel til DB til retrive detaljene (som bør vurdere tilgangsnivå) og kryptere brukerdetaljer i token. Din token bør inneholde tilgangsnivået.

  3. På hver forespørsel, vil du ha token i overskriftene, de-krypten token, og angi detaljene tilgangsnivåer (res.locals bør være det ideelle stedet for å sette tokens).

   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.`)
        }
    }

relevante delen

Siden du setter res.status(403).send({error: { status:403, message:'Access denied.'}});det er fornuftig at det ikke vil flytte til neste mellomvare.

Siden for et API-kall kan du *Probablysende overskrifter gang Som foreslått av Jérémie L skape en eneste ny mellomvare ville være den beste tilnærmingen

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();
  }
}
Svarte 09/10/2019 kl. 13:59
kilden bruker

stemmer
0

Opprett en ny funksjon, f.eks isAuthorizedfor å håndtere den logikken.

Hvis du ringer [verify, admin, moderator]separat de ikke er avhengig av hverandre.

rute:

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.'}});
}

mellomvare:

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;
}

Jeg tror du må endre verify(req), admin(req)og moderator(req).

Svarte 09/10/2019 kl. 13:06
kilden bruker

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