2017-11-24 14 views
6

Tôi đang thử dùng node_acl với passport-local. Khi tôi chạy mã của mình, tôi không thể bảo mật tuyến đường cho admin-user'/admin' và tôi được chuyển hướng đến trang /login.ACL - Triển khai ACL cùng với hộ chiếu

Tìm dưới dụ Runnable tối thiểu của tôi:

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: '[email protected]', 
    role: 'admin', 
}, 
{ 
    id: 2, 
    username: 'user', 
    password: 'user', 
    email: '[email protected]', 
    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 

gợi ý Bất kỳ lý do tại sao con đường, /admin không thể được gọi chỉ là admin user?

Cảm ơn bạn đã trả lời!

+0

những gì hiện '/ lợi nhuận tuyến đường status' của bạn cho bạn khi bạn đã đăng nhập với người dùng. Sau khi một số thử nghiệm tôi đã nhận 'HttpError: Không đủ quyền truy cập tài nguyên' khi tôi cố gắng nhấn'/admin' đăng nhập như người dùng – Stamos

Trả lời

2

Tôi không thể chạy mã "runnable" của bạn nên tôi đã thay đổi một chút để kiểm tra. Vì vậy, sau một số thử nghiệm có vẻ như nó hoạt động tốt. Bạn cũng có thể kiểm tra nó?

Sử dụng Postman Tôi đã làm một POST trên /login?username=user&password=user

Sau đó tôi đã làm một GET trên `/ tình trạng và tôi đã nhận

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

Sau đó, tôi đã làm một GET trên /admin và tôi đã nhận

<!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> 

Sau đó, tôi đăng nhập với tư cách quản trị viên và khi tôi gọi lại là /admin, tôi đã nhận được admin

Tôi phải thay đổi app.post('/login'). Nếu tôi không làm req.login thì passport.serializeUser chưa bao giờ được gọi, cookie không chính xác dẫn đến phiên xấu.

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

Tất cả các mã:

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: '[email protected]', 
    role: 'admin', 
}, 
{ 
    id: 2, 
    username: 'user', 
    password: 'user', 
    email: '[email protected]', 
    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 
+0

Thx cho câu trả lời của bạn! Một câu hỏi nữa, tại sao bạn đã thêm hàm 'setTimout' vào hàm' accessControl'? – mrquad

+0

Hơn nữa, tại sao bạn đã thêm: 'req.logIn (người dùng, (err) => {// <- Đăng nhập người dùng trong tiếp theo() })', không nên người dùng đã đăng nhập qua hộ chiếu? Tôi đánh giá cao câu trả lời của bạn! – mrquad

+0

Bỏ qua setTimeout, tôi muốn kiểm tra xem người dùng có nằm trong nhóm chính xác hay không. Tôi không biết 100% như thế nào acl hoạt động vì vậy tôi chờ đợi một chút – Stamos

Các vấn đề liên quan