Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Any ideas to enable a similar logic on frontend code #29

Open
lorinkoz opened this issue Jun 6, 2020 · 4 comments
Open

Any ideas to enable a similar logic on frontend code #29

lorinkoz opened this issue Jun 6, 2020 · 4 comments

Comments

@lorinkoz
Copy link

lorinkoz commented Jun 6, 2020

Amazing package! ⭐

Now, when you have such a fine grained backend permissioning system, it becomes super helpful to be able to translate that into the frontend code (Javascript) so that you can control which actions to show/allow based on the expected backend permission. For instance, if you know that certain role doesn't have access to perform a "create" in a given viewset, it would be useful to know that in the frontend so as to block/hide the respective create button when the user has that role.

Any ideas on how something like this could be achievable?

Again, fantastic package!

@rsinger86
Copy link
Owner

Thanks, I'm glad you like it :) I've thought about how this could be done a bit in the past, because I've had this use case as well. My idea was roughly along these lines:

policy_registry = AccessPolicyRegistery()

// code to collect all access policies in your project

for policy in policies:
     policy_registry.add(policy)

policy_registry.get_allowed_actions(user)

get_allowed_actions would iterate the policies and collect actions that the user can perform from statements where the user matches the principal.

It may be possible to automatically build the registry by scanning the app directories or by examining the policies attached to all the Django views in the project. The registry would only need to get built once. Depending on project requirements, there could be some period of per-user caching.

@lorinkoz
Copy link
Author

lorinkoz commented Jun 6, 2020

Nice. Some additional thoughts here, considering the possibility of contributing:

  • The "resource" equivalent is missing because it's not necessary, as it's implied when you attach a policy to a viewset (the viewset becomes the resource). However, in order to properly query permissions in the frontend (which is a viewset agnostic situation), a "resource" must be specified when registering all policies. Do you have any defined conventions about this? This is what I'm thinking in Javascript:
checkPermission(user, resource, action)
  • Any permission checking logic that requires a "request" object would be impossible to translate outside the request/response cycle. Have you considered the possibility of depending on a user instead, with an optional request/view to augment the check? I am thinking that a number of statements will depend only on the user, while others will depend on other elements from the request/view. The former would be translatable, whereas the latter would not. Statements with conditions will most likely be non-translatable. It would be a tradeoff the user would have to decide, but at least those statements that depend only on the user would be perfectly fit for checking in Javascript.

@rsinger86
Copy link
Owner

I appreciate the thoughtful ideas here.

For you first point, I see two possibilities:
a) The resource is defined as a class attribute on the policy, eg

class ArticleAccessPolicy(AccessPolicy):
    resource_name = "article"

b) The resource name is defined as a class attribute on the view set or with a decorator on the api_view function.

In either case, a magic default for the resource_name could be derived from the URL path configured for the view ('/articles'), or the name of the viewset or viewset model, or the api_view function.

What do you think about those options?

For your second point, I think you're on to something. I agree that the view parameter should be optional. The request method is examined for the <safe_methods> action variable, but it seems like the request could easily be simulated for an artificial permission check.

Say your JS application makes a call to your DRF enpoint:

POST /permission-check/
{
   'user': 4,
   'http_method': 'POST',
   'resource': 'article',
   'action': 'create'
}

The permission check code could construct a fake request object using the http_method and user. Any checks that require the view object or a condition check could fail by default (but maybe the response could note that these are qualified failures).

@lorinkoz
Copy link
Author

lorinkoz commented Jun 7, 2020

For the first point everything makes sense. Options (a) and (b) both have useful cases, so maybe the only pending decision is the order of precedence.

For the second point, all good. My only concern with constructing a fake request is that sometimes people rely on the request being augmented by middleware. How to overcome this?

Your example of a permission checking endpoint would work perfectly as the canonical way for pre-checking. I am also thinking in taking that one step further and generating a Javascript file on the fly so that the check can be made in the client with the permissions that can be registered at the time of starting the server.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants