- the current user is of the correct type to access that view
- the current user has access to the request(s) she's trying to view - the request id's are part of the url
Pretty simple, right? So I have a piece of boilerplate code stuck in the front of my views that does the following:
- get the logged in user
- redirect to login page if no user or anonymous user
- get the logged in users' profile, and from that get their account id/object
- if the user doesn't have a profile, they shouldn't be here at all so fail with an 'access denied' message
- if the user doesn't have an account, they may be an admin - check for admin privs (is_staff)
- if they're not an admin and don't have an account, their user/account is invalid and support needs to fix them - tell them that before logging them out.
These steps basically validate the user has access to the app. Based on whether we're in a 'view/edit' or 'list/browse' type context, one of the following happens next:
- To ensure they have access to the 'current' order, we lookup the orderid in the set associated with their account.
- If it's not there, it's probably somebody else's order and we give them an 'access-denied', unless
- they are staff members, in which case they are granted access based on a class level permissions system.
- To discover the set of orders the user has access to, we do an account based database query, unless the user is staff, in which case we just list everything
Over time the boilerplate starts to smell. Small variations arise from method to method based on specific stuff I need to do, or I figure a better, more elegant way to do the same thing and don't bother changing all the other boilerplates. Worse, when something global changes - for example, the emergence of 'staff' users - I have to make the same change in a lot of places, possibly in slightly different ways.
My answer to this? Middleware!
Since I basically always need the account of the logged in user, I created a middleware class to set that in the current request when it was available. This class also validates the current user is valid and permitted application access based on their 'role' or account type, so each view just has to handle the variant behaviour based on the staff/not staff dichotomy. Since this logic may vary depending on the view, I think its appropriate to leave the view this work.
Simple stuff, probably, but cool anyway.