Created
February 2, 2022 14:06
-
-
Save sumbad/48bce0a19d9bfed6bec0a87689592dad to your computer and use it in GitHub Desktop.
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
import http from 'http'; | |
import { newEnforcer, newModel, StringAdapter, Util } from 'casbin'; | |
//#region SERVER | |
const hostname = '127.0.0.1'; | |
const port = 3005; | |
const server = http.createServer(async (request, response) => { | |
const isNext = await authMiddleware(request, response); | |
if (!isNext) { | |
return; | |
} | |
switch (true) { | |
case request.url.startsWith('/article'): | |
articleController(request, response); | |
break; | |
case request.url.startsWith('/admin_panel'): | |
adminController(request, response); | |
break; | |
default: | |
notFound(request, response); | |
break; | |
} | |
}); | |
server.listen(port, hostname, () => { | |
console.log(`Server running at http://${hostname}:${port}/`); | |
}); | |
//#endregion SERVER | |
//#region CONTROLLERS | |
function articleController(req, res) { | |
if (req.method === 'GET' && req.url === '/article') { | |
res.statusCode = 200; | |
res.setHeader('Content-Type', 'text/plain'); | |
res.end('Read an article'); | |
return; | |
} | |
if (req.method === 'POST' && req.url === '/article/find') { | |
res.statusCode = 200; | |
res.setHeader('Content-Type', 'text/plain'); | |
res.end('Find an article by filter'); | |
return; | |
} | |
if (req.method === 'POST' && req.url === '/article/write') { | |
res.statusCode = 200; | |
res.setHeader('Content-Type', 'text/plain'); | |
res.end('Write a new article'); | |
return; | |
} | |
notFound(req, res); | |
} | |
function adminController(req, res) { | |
if (req.method === 'GET' && req.url === '/admin_panel') { | |
res.statusCode = 200; | |
res.setHeader('Content-Type', 'text/plain'); | |
res.end('Admin panel'); | |
return; | |
} | |
if (req.method === 'PUT' && req.url === '/admin_panel/author') { | |
res.statusCode = 200; | |
res.setHeader('Content-Type', 'text/plain'); | |
res.end('Create a new author'); | |
return; | |
} | |
notFound(req, res); | |
} | |
function notFound(req, res) { | |
res.statusCode = 404; | |
res.end(); | |
} | |
//#endregion CONTROLLERS | |
//#region MIDDLEWARE | |
async function authMiddleware(req, res) { | |
// Get user token | |
// const token = req.headers['authorization']; | |
// Validate token etc... | |
// Get user name and groups from the token | |
// for simplification, we will use values directly from headers | |
const name = req.headers['name']; | |
const groups = req.headers['groups']?.split(','); | |
if (name == null || groups == null) { | |
res.statusCode = 401; | |
res.end(JSON.stringify({ message: 'Unauthorized' })); | |
return false; | |
} | |
const model = ` | |
[request_definition] | |
r = sub, obj, act | |
[policy_definition] | |
p = sub, obj, act | |
[role_definition] | |
g = _, _ | |
g2 = _, _ | |
[policy_effect] | |
e = some(where (p.eft == allow)) | |
[matchers] | |
m = g(r.sub, p.sub) && (g2(r.obj, p.obj) || keyMatch(r.obj, p.obj)) && keyMatch(r.act, p.act) | |
`; | |
const policy = ` | |
p, group:user, entity:article, read | |
p, group:author, entity:article, write | |
p, group:admin, *, * | |
p, group:user, /article/find, * | |
g, group:author, group:user | |
g, group:admin, group:author | |
g2, /article, entity:article | |
g2, /article/*, entity:article | |
`; | |
const sub = name; // use a user name as subject | |
const obj = req.url; // use URL as object | |
const act = req.method === 'GET' ? 'read' : 'write'; // GET is 'read', others are 'write' | |
const enforcer = await newEnforcer(newModel(model), new StringAdapter(policy)); | |
enforcer.addNamedMatchingFunc('g2', Util.keyMatchFunc); | |
const addGroupsToUser = async (sub, groups) => { | |
await Promise.all(groups.map((group) => enforcer.addRoleForUser(sub, `group:${group}`))); | |
}; | |
await addGroupsToUser(name, groups); | |
const isPermitted = await enforcer.enforce(sub, obj, act); | |
if (!isPermitted) { | |
res.statusCode = 403; | |
res.end(JSON.stringify({ message: 'Forbidden' })); | |
return false; | |
} | |
return true; | |
} | |
//#endregion MIDDLEWARE |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment