我正在尝试使用node_aclpassport-local。运行代码时,我无法保护admin-user '/admin'的路由,因此将我重定向到/login页面。

在下面的最小可运行示例中查找:

require('dotenv').config()
const express = require('express')
// const fs = require('fs')
const path = require('path')
const logger = require('morgan')
const bodyParser = require('body-parser')
const cookieParser = require('cookie-parser')
const session = require('express-session')
const passport = require('passport')
const LocalStrategy = require('passport-local').Strategy
const ACL = require('acl')

// load user.json file
// const d = fs.readFileSync(path.join(__dirname, '/../data/user.json'))
// const userObj = JSON.parse(d)
const userObj = [{
  id: 1,
  username: 'admin',
  password: 'admin',
  email: 'admin@admin.com',
  role: 'admin',
},
{
  id: 2,
  username: 'user',
  password: 'user',
  email: 'user@user.com',
  role: 'user',
},
]

const app = express()

// view engine setup
app.set('views', path.join(__dirname, 'views'))
app.set('view engine', 'pug')
app.use(logger(process.env.LOG_ENV))
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({
  extended: false,
}))
app.use(express.static(path.join(__dirname, '/../public')))
app.use(cookieParser())

app.use(session({
  secret: 'super-mega-hyper-secret',
  resave: false,
  saveUninitialized: false,
}))

/**
 * Passport Local
 */
app.use(passport.initialize())
app.use(passport.session())

function authenticate() {
  passport.serializeUser((user, done) => {
    done(null, user.id)
  })

  passport.deserializeUser(async(id, done) => {
    //        const user = await serviceAuth.findById(id)
    const user = userObj.find(item => item.id === id)
    done(null, user)
  })

  // Sign in with username and Password
  passport.use('local', new LocalStrategy({
    usernameField: 'username',
  }, async(username, password, done) => {
    const user = userObj.find(item => item.username === username)
    done(null, user)
  }))
}

const isAuthenticated = (req, res, next) => {
  if (req.isAuthenticated()) {
    res.locals.user = req.session.user
    return next()
  }
  res.redirect('login')
}
authenticate()

/**
 * Node ACL
 */

function accessControl() {
  const nodeAcl = new ACL(new ACL.memoryBackend())

  nodeAcl.allow([{
    roles: 'admin',
    allows: [{
      resources: '/admin',
      permissions: '*',
    }],
  }, {
    roles: 'user',
    allows: [{
      resources: '/dashboard',
      permissions: 'get',
    }],
  }, {
    roles: 'guest',
    allows: [],
  }])

  // Inherit roles
  //  Every user is allowed to do what guests do
  //  Every admin is allowed to do what users do
  nodeAcl.addRoleParents('user', 'guest')
  nodeAcl.addRoleParents('admin', 'user')

  nodeAcl.addUserRoles(1, 'admin')
  nodeAcl.addUserRoles(2, 'user')
  nodeAcl.addUserRoles(0, 'guest')

  return nodeAcl
}

/*
function checkPermission(resource, action) {
  const access = accessControl()

  return (req, res, next) => {
    const uid = req.session.user.id
    access.isAllowed(uid, resource, action, (err, result) => {
      if (result) {
        next()
      } else {
        const checkError = new Error('User does not have permission to perform this action on this resource')
        next(checkError)
      }
    })
  }
} */

const getCurrentUserId = (req) => {
  console.log(req)
  req.user && req.user.id.toString() || false
}

const access = accessControl()

// Routes
app.get('/login', (req, res) => {
  res.render('login')
})

app.post('/login', (req, res, next) => {
  passport.authenticate('local', (err, user) => {
    if (err) return next(err)
    if (!user) {
      return res.status(401).json({
        error: 'Email or password is incorrect.',
      })
    }

    return res.render('dashboard')
  })(req, res, next)
})

app.get('/dashboard', [isAuthenticated, access.middleware()], (req, res) => {
  res.render('dashboard')
})

app.get('/admin', [isAuthenticated, access.middleware()], (req, res) => {
  res.render('admin')
})

app.get('/status', (request, response) => {
  access.userRoles(getCurrentUserId(request), (error, roles) => {
    response.send(`User: ${JSON.stringify(request.user)} Roles: ${JSON.stringify(roles)}`)
  })
})

// Start Server
const port = process.env.APP_PORT || 8080
const host = process.env.APP_URL || 'localhost'

app.listen(port, host, () => {
  console.log(`Listening on ${host}:${port}`)
})

module.exports = app

为什么不能仅将/admin称为路线admin user的任何建议?

预先感谢您的答复!

最佳答案

我无法运行您的“可运行”代码,因此我对其进行了一些更改以进行检查。
因此,经过一些测试,它似乎可以正常工作。你也可以检查一下吗?

使用POSTMAN我在POST上做了一个/login?username=user&password=user
之后,我在`/status'上做了一个GET,我得到了

User: {"id":2,"username":"user","password":"user","email":"user@user.com","role":"user"} Roles: []

然后我在GET上做了一个/admin,我得到了
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>Error</title>
    </head>
    <body>
        <pre>HttpError: Insufficient permissions to access resource
            <br> &nbsp; &nbsp;at C:\Users\stamoulis.zamanis\Desktop\aclTest\node_modules\acl\lib\acl.js:705:14
            <br> &nbsp; &nbsp;at tryCatcher (C:\Users\stamoulis.zamanis\Desktop\aclTest\node_modules\bluebird\js\release\util.js:16:23)
            <br> &nbsp; &nbsp;at Promise.successAdapter [as _fulfillmentHandler0] (C:\Users\stamoulis.zamanis\Desktop\aclTest\node_modules\bluebird\js\release\nodeify.js:23:30)
            <br> &nbsp; &nbsp;at Promise._settlePromise (C:\Users\stamoulis.zamanis\Desktop\aclTest\node_modules\bluebird\js\release\promise.js:566:21)
            <br> &nbsp; &nbsp;at Promise._settlePromise0 (C:\Users\stamoulis.zamanis\Desktop\aclTest\node_modules\bluebird\js\release\promise.js:614:10)
            <br> &nbsp; &nbsp;at Promise._settlePromises (C:\Users\stamoulis.zamanis\Desktop\aclTest\node_modules\bluebird\js\release\promise.js:693:18)
            <br> &nbsp; &nbsp;at Async._drainQueue (C:\Users\stamoulis.zamanis\Desktop\aclTest\node_modules\bluebird\js\release\async.js:133:16)
            <br> &nbsp; &nbsp;at Async._drainQueues (C:\Users\stamoulis.zamanis\Desktop\aclTest\node_modules\bluebird\js\release\async.js:143:10)
            <br> &nbsp; &nbsp;at Immediate.Async.drainQueues (C:\Users\stamoulis.zamanis\Desktop\aclTest\node_modules\bluebird\js\release\async.js:17:14)
            <br> &nbsp; &nbsp;at runCallback (timers.js:789:20)
            <br> &nbsp; &nbsp;at tryOnImmediate (timers.js:751:5)
            <br> &nbsp; &nbsp;at processImmediate [as _immediateCallback] (timers.js:722:5)
        </pre>
    </body>
</html>

然后我以管理员身份登录,当我再次调用/admin时,我得到了admin
我不得不更改app.post('/login')。如果我不做req.login,那么就不会调用passport.serializeUser,那么cookie是不正确的,从而导致 session 不良。
app.post('/login', (req, res, next) => {
  passport.authenticate('local', (err, user) => {
    if (err) return next(err)
    if (!user) {
      return res.status(401).json({
        error: 'Email or password is incorrect.',
      })
    }
     req.logIn(user, function (err) { // <-- Log user in
       next();
    });


  })(req, res, next)
},function(req,res){
 res.send('dashboard')
})

所有代码:
require('dotenv').config()
const express = require('express')
// const fs = require('fs')
const path = require('path')
const logger = require('morgan')
const bodyParser = require('body-parser')
const cookieParser = require('cookie-parser')
const session = require('express-session')
const passport = require('passport')
const LocalStrategy = require('passport-local').Strategy
const ACL = require('acl')

// load user.json file
// const d = fs.readFileSync(path.join(__dirname, '/../data/user.json'))
// const userObj = JSON.parse(d)
const userObj = [{
  id: 1,
  username: 'admin',
  password: 'admin',
  email: 'admin@admin.com',
  role: 'admin',
},
{
  id: 2,
  username: 'user',
  password: 'user',
  email: 'user@user.com',
  role: 'user',
},
]

const app = express()

// view engine setup
app.set('views', path.join(__dirname, 'views'))
app.set('view engine', 'pug')
app.use(logger(process.env.LOG_ENV))
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({
  extended: false,
}))
app.use(express.static(path.join(__dirname, '/../public')))
app.use(cookieParser())

app.use(session({
  secret: 'super-mega-hyper-secret',
  resave: false,
  saveUninitialized: false,
}))



function authenticate() {
  passport.serializeUser((user, done) => {
    done(null, user.id)
  })

  passport.deserializeUser((id, done) => {
    //        const user = await serviceAuth.findById(id)
    const user = userObj.find(item => item.id === id)
    done(null, user)
  })

  // Sign in with username and Password
  passport.use('local', new LocalStrategy({
    usernameField : 'username',
        passwordField : 'password'
  }, async(username, password, done) => {
    const user = userObj.find(item => item.username === username)
    done(null, user)
  }))
}

const isAuthenticated = (req, res, next) => {
  if (req.isAuthenticated()) {
    res.locals.user = req.session.user
    return next()
  }
  res.redirect('login')
}
authenticate()


/**
 * Passport Local
 */
app.use(passport.initialize())
app.use(passport.session())

/**
 * Node ACL
 */

function accessControl() {
  const nodeAcl = new ACL(new ACL.memoryBackend())

  nodeAcl.allow([{
    roles: 'admin',
    allows: [{
      resources: '/admin',
      permissions: '*',
    }],
  }, {
    roles: 'user',
    allows: [{
      resources: '/dashboard',
      permissions: 'get',
    }],
  }, {
    roles: 'guest',
    allows: [],
  }])

  // Inherit roles
  //  Every user is allowed to do what guests do
  //  Every admin is allowed to do what users do
  nodeAcl.addRoleParents('user', 'guest')
  nodeAcl.addRoleParents('admin', 'user')

  nodeAcl.addUserRoles(1, 'admin')
  nodeAcl.addUserRoles(2, 'user')
  nodeAcl.addUserRoles(0, 'guest')

  return nodeAcl
}

/*
function checkPermission(resource, action) {
  const access = accessControl()

  return (req, res, next) => {
    const uid = req.session.user.id
    access.isAllowed(uid, resource, action, (err, result) => {
      if (result) {
        next()
      } else {
        const checkError = new Error('User does not have permission to perform this action on this resource')
        next(checkError)
      }
    })
  }
} */

const getCurrentUserId = (req) => {
  console.log(req)
  req.user && req.user.id.toString() || false
}

const access = accessControl()

// Routes
app.get('/login', (req, res) => {
  res.send('login')
})

app.post('/login', (req, res, next) => {
  passport.authenticate('local', (err, user) => {
    if (err) return next(err)
    if (!user) {
      return res.status(401).json({
        error: 'Email or password is incorrect.',
      })
    }
     req.logIn(user, function (err) { // <-- Log user in
       next();
    });


  })(req, res, next)
},function(req,res){
 res.send('dashboard')
})

app.get('/dashboard', [isAuthenticated, access.middleware()], (req, res) => {
  res.send('dashboard')
})

app.get('/admin', [isAuthenticated, access.middleware()], (req, res) => {
  res.send('admin')
})

app.get('/status', (request, response) => {
  access.userRoles(getCurrentUserId(request), (error, roles) => {
    response.send(`User: ${JSON.stringify(request.user)} Roles: ${JSON.stringify(roles)}`)
  })
})

// Start Server
const port = process.env.APP_PORT || 3335
const host = process.env.APP_URL || 'localhost'

app.listen(port, host, () => {
  console.log(`Listening on ${host}:${port}`)
})

module.exports = app

09-10 10:56
查看更多