-
-
Save Kurukshetran/60b008e680ab8861a2bee62d488141bd to your computer and use it in GitHub Desktop.
Express.js role-based permissions middleware
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// the main app file | |
import express from "express"; | |
import loadDb from "./loadDb"; // dummy middleware to load db (sets request.db) | |
import authorize from "./authorization"; // middleware for doing authorization | |
import permit from "./permission"; // middleware for checking if user's role is permitted to make request | |
let app = express(), | |
api = express.Router(); | |
// first middleware will setup db connection | |
app.use(loadDb); | |
// check authorization for each request | |
// will set `request.user` | |
app.use(authorize); | |
// setup permission middleware, | |
// check `request.user.role` and decide if ok to continue | |
app.use("/api/private", permit("admin")); | |
app.use(["/api/foo", "/api/bar"], permit("account-owner", "account-member")); | |
// setup requests handlers | |
api.get("/private/whatever", (req, res) => response.json({whatever: true})); | |
api.get("/foo", (req, res) => response.json({currentUser: req.user})); | |
api.get("/bar", (req, res) => response.json({currentUser: req.user})); | |
// setup permissions based on HTTP Method | |
// account creation is public | |
api.post("/account", (req, res) => req.json({message: "created"})); | |
// account update & delete (PATCH & DELETE) are only available to account owner | |
api.patch("/account", permit('account-owner'), (req, res) => req.json({message: "updated"})); | |
api.delete("/account", permit('account-owner'), (req, res) => req.json({message: "deleted"})); | |
// viewing account "GET" available to account owner and account member | |
api.get("/account", permit('account-member', 'account-owner'), (req, res) => req.json({currentUser: request.user})); | |
// mount api router | |
app.use("/api", api); | |
// start 'er up | |
app.listen(process.env.PORT || 3000); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// middleware for authentication | |
export default function authorize(req, res, next) { | |
let apiToken = req.headers['x-api-token']; | |
req.db | |
.users | |
.findByApiKey(apiToken) | |
.then(user => req.user = user) // set user on-success | |
.finally(next); // always continue to next middleware | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// dummy middleware for db (set's request.db) | |
export default function loadDb(req, res, next) { | |
// dummy db | |
request.db = { | |
users: { | |
findByApiKey: token => new Promise((resolve, reject) => { | |
switch { | |
case (token == '1234') { | |
resolve({role: 'account-owner', id: 1234}); | |
break; | |
case (token == '5678') { | |
resolve({role: 'account-member', id: 5678}); | |
break; | |
default: | |
reject(); | |
} | |
}) | |
} | |
}; | |
next(); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// middleware for doing role-based permissions | |
export default function permit(...allowed) { | |
let isAllowed = role => _.indexOf(allowed, role) > -1; | |
// return a middleware | |
return (req, res, next) => { | |
if (req.user && isAllowed(req.user.role)) | |
next(); // role is allowed, so continue on the next middleware | |
else { | |
response.status(403).json({message: "Forbidden"}); // user is forbidden | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment