Closed maximilianschmitt closed 7 years ago
@maximilianschmitt Can you provide a simple example for an admin viewing the admin route?
@mylastore I'm sorry, which admin route?
If a normal user or guest wants to access an admin route or page how can I prevent that.
@maximilianschmitt I think you can do this -
Roles - user, owner, customer Resource - product
ac.grant('user').readAny('product', ['title', 'description']);
ac.grant('customer').extend('user').readOwn('product', ['title', 'description', 'downloadLink']);
ac.grant('owner').extend('user').readOwn('product', ['*'])
Actually, "own" and "any" covers it all.
Don't limit what "own" could stand for.
Let's grant permissions first:
(Note: I suggest you don't name a role owner
. Any role can own one resource or the other. Semantically it's better when you name your roles by their purpose. e.g. user
, admin
, editor
, etc...)
const ac = new AccessControl();
ac.grant('guest')
.readAny('products', ['title', 'description']);
const vAttrs = ['title', 'description', 'downloadLink', 'downloadsCount'];
ac.grant('vendor')
.extend('guest')
.createOwn('products', vAttrs)
.readOwn('products', vAttrs);
ac.grant('customer')
.extend('guest')
.readOwn('products', ['title', 'description', 'downloadLink']);
So when querying for permissions; (pls see this) Own requires you to also check for the actual possession. The possession in these cases, indicates that:
vendor
role, "own" means "manufactured by"customer
role, "own" means "purchased by"/products/:productId
const product = getProduct(Number(req.params.productId));
// "purchased by" OR "manufactured by" —> both means own'ed
const isOwned = isPurchasedBy(req.user.id, product.id)
|| product.vendorId === user.id;
const permission = isOwned
? ac.can(req.user.role).readOwn('products')
: ac.can(req.user.role).readAny('products');
if (permission.granted) {
// attrs will differ depending on the actual role queried
console.log(permission.attributes);
res.json(permission.filter(product));
}
See? Owning a resource could mean many things. It's AccessControl.js, trying to be non-opinionated as much as possible; leaving many choices to the developer.
With a manager role - the objective would be to have the manager able to see and edit all fields for a user object - but only for their team. I assume the correct method would be to apply a createAll on the user object but handle the filter to restrict just people that report to them separately/manually. Is there a better method such as creating an addition resource for each team: TeamMember
Maybe you can use the attribut functionality to handle this use case. Add an attribute with the team name on the manager role to be able to filter access.
@glenarama you could consider a teamManager
role. i.e. If the user belongs to own team, teamManager
can update... Check out this example.
Thanks Onury - So is it something like:
ac.grant('admin').updateAll('user') ac.grant('user').updateOwn('user') ac.grant('manager').updateOwn('teamUser')
const can = ac.can(user.role);
If(isManager(userobj)) can.updateOwn('teamUser') else can.updateOwn('user')
updateAll()
method. I guess you mean updateAny()
"teamUser"
resource, you need "teamManager"
role.EDIT: This depends on the app design though. If the view/route lists team member accounts, you could have a teamMemberAccount
resource. Then implementation could be changed a bit...
"account"
rather than "user"
(avoid confusion since we also have a role named "user"
)// grants
ac.grant('admin').updateAny('account'); // grant #1
ac.grant('user').updateOwn('account'); // grant #2
ac.grant('teamManager').updateOwn('account'); // grant #3
// checks
const isOwnAccount = user.id === targetUserId;
const isOwnTeamMemberAccount = isTeamManagerOf(user.id, targetUserId);
const permission = isOwnAccount || isOwnTeamMemberAccount
? ac.can(user.role).updateOwn('account') // #2, #3
: ac.can(user.role).updateAny('account'); // #1
That pseudo function could be like this:
function isTeamManagerOf(managingUserId, memberUserId) {
const managedTeams = getManagedTeamsOf(managingUserId); // array of team names
const teamsToCheck = getTeamsOf(memberUserId); // array of team names
return teamsToCheck.some(teamName => {
return managedTeams.indexOf(teamName) >= 0;
});
}
... or it could directly query a database...
Gotcha - Thanks. I was imagining the use case where the attribute permissions may be different from the managers Own account vs their employee's account. Three different permission types e.g:
Admin edit anything Manager edit anything in team User edit anything except field "title"
Sorry didn't clarify this in the original question. I think i do need a seperate resource to enable that structure.
Hi!
I stumbled upon accesscontrol while looking for existing solutions to some ABAC and I really like the API!
Question
Can I have more possession types than simply "Owner" and "Any"?
Use Case
Let's say I have a market place where people can sell products and others can buy them. I could have a
Product
resource where:title, description
owner
(vendor) can viewtitle, description, downloadLink, downloadsCount
customer
(user who bought the product) can viewtitle, description, downloadLink
Thanks, Max