I'm wondering what the best approach for adding roles to users / permissions to Handler
s or resources in Yesod is. Does anyone have prior art for this kind of thing? Are there any approaches that leverage the type-system to help prevent slip-ups (and also keep database queries to check for ownership etc to a minimum)?
EDIT: Sorry for missing this before-hand - I do notice that there's actually a section, which I somehow missed at first glance (I think because there's no mention of access/roles/permissions), on Authorization in the Yesod book. This appears to do access control at the router level with a write flag for PUT/POST. It doesn't seem terribly sophisticated by itself, but it looks just fine for building abstractions on top...
Under Access Settings, click New. Under New Setting, use the drop-down list under Select role to choose a role for this user. Click New again to add additional access scopes, or click OK to finish.
By adding a user to a role group, the user has access to all the roles in that group. If they are removed, access becomes restricted. Users may also be assigned to multiple groups in the event they need temporary access to certain data or programs and then removed once the project is complete.
One role-based access control example is a set of permissions that allow users to read, edit, or delete articles in a writing application. There are two roles, a Writer and a Reader, and their respective permission levels are presented in this truth table. Using this table, you can assign permissions to each user.
In the time since posting this I have found this very helpful blog post Abstracting permissions with Yesod by Felipe Lessa. It builds on top of the existing isAuthorized
function, demonstrating a simple strategy for adding roles to users and access permissions to resources.
Basically it defines
isAuthorizedTo :: Maybe (UserId, User) -> [Permission] -> YesodDB sub Blog AuthResult
permissionsRequiredFor :: Route Blog -> Bool -> [Permission]
in order to get something like this:
isAuthorized route isWrite = do
mauth <- maybeAuth
runDB $ mauth `isAuthorizedTo` permissionsRequiredFor route isWrite
where permissionsRequiredFor
returns a list of some user defined Permission
data type like this:
data Permission = Post -- Permission to create blog posts
| CommentOn EntryId -- Permission to comment on a particular blog entry
| View EntryId -- Permission to view a particular blog entry
This is simple and practical, thank you Felipe. (It might be nice if someone tries to capture this kind of thing in library form and publish to Hackage in order to find & drop access control into your app as quickly as possible! Alternatively perhaps in the Yesod scaffold?)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With