rsinger86 / drf-access-policy

Declarative access policies/permissions modeled after AWS' IAM policies.
https://rsinger86.github.io/drf-access-policy/
MIT License
472 stars 50 forks source link
access-control authorization declarative django django-rest-framework iam permissions

Django REST - Access Policy

Package version Python versions

This project brings a declaritive, organized approach to managing access control in Django REST Framework projects. Each ViewSet or function-based view can be assigned an explicit policy for the exposed resource(s). No more digging through views or seralizers to understand access logic -- it's all in one place in a format that less technical stakeholders can understand. If you're familiar with other declaritive access models, such as AWS' IAM, the syntax will be familiar.

In short, you can start expressing your access rules like this:

class ArticleAccessPolicy(AccessPolicy):
    statements = [
        {
            "action": ["list", "retrieve"],
            "principal": "*",
            "effect": "allow"
        },
        {
            "action": ["publish", "unpublish"],
            "principal": ["group:editor"],
            "effect": "allow"
        }
    ]

This project has complete test coverage and the base AccessPolicy class is only ~150 lines of code: there's no magic here.

Additionally, this project also provides FieldAccessMixin that can be added to a serializer to dynamically set fields to read_only, based on the access policy. Assign the appropriate access policy class inside the Meta declaration. See example below for how this works:

class UserAccountAccessPolicy(AccessPolicy):
    statements = [
        {"principal": "group:admin", "action": ["create", "update"], "effect": "allow"},
        {
            "principal": "group:dev",
            "action": ["update", "partial_update"],
            "effect": "allow",
        },
    ]

    field_permissions = {"read_only": [{"principal": "group:dev", "fields": "status"}]}

class UserAccountSerializer(FieldAccessMixin, serializers.ModelSerializer):
  class Meta:
    model = UserAccount
    fields = ["username", "first_name", "last_name", "status"]
    access_policy = UserAccountAccessPolicy

# Incoming POST/PUT/PATCH request from a user in group:dev...
# serializer = UserAccountSerializer(account, context={'request': request})
# print(serializer.fields["status"].read_only) -> True

:warning: 1.0 Breaking Change :warning:

See migration notes if your policy statements combine multiple conditions into boolean expressions.


Documentation: https://rsinger86.github.io/drf-access-policy

Source Code: https://github.com/rsinger86/drf-access-policy


Changelog

1.5 (March 2023)

1.4 (March 2023)

1.3 (October 2022)

1.2 (October 2022)

1.1.2 (July 2022)

1.1.1 (April 2022)

1.1.0 (August 2021)

1.0.1 (July 2021)

1.0.0 (July 2021)

0.9.2 (July 2021)

0.9.1 (July 2021)

0.9.0 (April 2021)

0.8.7 (February 2021)

0.8.6 (January 2021)

0.8.5 (January 2021)

0.8.1 (October 2020)

0.8.0 (September 2020)

0.7.0 (August 2020)

0.6.2 (July 2020)

0.6.1 (June 2020)

0.6.0 (May 2020)

0.5.1 (December 2019)

0.5.0 (September 2019)

0.4.2 (June 2019)

0.4.0 (June 2019)

0.3.0 (May 2019)

0.2.0 (May 2019)

0.1.0 (May 2019)

Testing

Tests are found in a simplified Django project in the /tests folder. Install the project requirements and do ./manage.py test to run them.

License

See License.