2017-11-24 200 views
6

Próbuję out node_acl z passport-local. Po uruchomieniu kodu nie mogę zabezpieczyć trasy dla admin-user'/admin' i jestem przekierowywany na stronę /login.ACL - Zaimplementuj acl razem z paszportem

Znajdź poniżej minimalnej moim runnable przykład:

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 

jakieś sugestie dlaczego trasa, /admin nie można nazwać tylko być admin user?

Z góry dziękuję za odpowiedzi!

+0

co robi '/ status' trasy powraca do ciebie, gdy jesteś zalogowany jako użytkownik. Po pewnym teście mam 'HttpError: Niewystarczające uprawnienia dostępu do zasobu' kiedy próbowałem trafić'/admin' zalogowałem się jako użytkownik – Stamos

Odpowiedz

2

Nie mogłem uruchomić twojego "działającego" kodu, więc zmieniłem go trochę, by to sprawdzić. Po kilku testach wydaje się, że działa dobrze. Czy możesz to sprawdzić?

Korzystanie POSTMAN Zrobiłem POST na /login?username=user&password=user

Potem zrobiłem GET na `/ status' i mam

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

Potem zrobiłem GET na /admin i mam

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

Potem zalogowałem się jako admin i kiedy zadzwoniłem /admin ponownie otrzymałem admin

Musiałem zmienić app.post('/login'). Gdybym nie zrobił req.login, to passport.serializeUser nigdy nie było wywoływane, ciasteczko nie było poprawne, co powodowało złą sesję.

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

Cały kod:

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 za odpowiedź! Jeszcze jedno pytanie, dlaczego dodałeś funkcję 'setTimout' w funkcji' accessControl'? – mrquad

+0

Co więcej, dlaczego dodałeś: 'req.logIn (user, (err) => {// <- Zaloguj użytkownika w next() })', czy użytkownik nie powinien być już zalogowany za pośrednictwem paszportu? Doceniam twoją odpowiedź! – mrquad

+0

Zignoruj ​​setTimeout, chciałem sprawdzić, czy użytkownicy są we właściwych grupach. Nie wiem w 100%, jak działa acl, więc czekałem trochę – Stamos