Django
The Oso Django integration adopts Django conventions and provides middleware, view decorators and ORM integrations to make it easier to use Oso with Django.
Installation
The Oso Django integration is available on
PyPI and can be installed using
pip
:
$ pip install django-oso
Usage
The django_oso
Django plugin contains a reusable Django app that makes
authorization with Oso and Django easy. To use, ensure django_oso
is in
INSTALLED_APPS
:
INSTALLED_APPS = [
'django_oso',
...
]
By default, django_oso
will consider policy files as source code and restart the
server on any changes. To prevent this, add the configuration option:
OSO_RELOAD_SERVER = False
to your application’s settings.py
file.
To reload policies on each request in DEBUG
mode without restarting the
server, you can use the ReloadPolicyMiddleware
as a complement to the above
configuration change.
Loading policies
django_oso
expects policy files to be included in the policy
directory
of each installed app. Upon startup, all .polar
files found in that
directory (or sub-directories) will be loaded using
oso.Oso.load_file()
. To load additional files outside of these
directories, call load_file()
on
django_oso.oso.Oso
.
Registering classes & models
Often, authorization rules will be expressed over Django models. Therefore,
django_oso
will register every model for each installed app upon startup as
a class with Oso. The django.http.HttpRequest
is also registered
under HttpRequest
. Django models are referenced in a Polar file using the
syntax app_name::ModelName
. If an app name contains .
, for example
django.contrib.auth
, it will be referenced in Oso as
django::contrib::auth
.
Additional classes can be registered as needed using
oso.Oso.register_class()
on django_oso.oso.Oso
.
Performing authorization
To authorize a request, use the django_oso.auth.authorize()
function.
It calls
is_allowed()
, but provides sensible defaults for working with
Django. The actor defaults to request.user
. The action
defaults to the method of the request.
resource
must be provided.
django_oso.auth.authorize()
can be used within route handlers, or in
the data access layer, depending upon how you want to express authorization.
Here’s a basic example in a route:
def get_expense(request, id):
try:
expense = Expense.objects.get(pk=id)
except Expense.DoesNotExist:
return HttpResponseNotFound()
authorize(request, expense, action="read")
return HttpResponse(expense.json())
Requiring authorization on every request
Since authorize()
is just a function call, it can be
forgotten. To enforce authorization on every request, use the
RequireAuthorization()
middleware. Any view that
does not call authorize()
or
skip_authorization()
will raise an exception.
Route authorization
One common usage of django_oso.auth.authorize()
is to perform authorization
based on the request object. The
authorize_request()
decorator does this:
from django_oso.decorators import authorize_request
@authorize_request
def auth_route(request):
pass
Rules can then be written using request attributes, like the path:
# Allow any actor to make a GET request to "/".
allow(_user: User, "GET", http_request: HttpRequest) if
http_request.path = "/";
To enforce route authorization on all requests (the equivalent of decorating
every route as we did above), use the
RouteAuthorization()
middleware during
initialization.
Example
Check out the Django integration example app on GitHub.
API Reference
The Django API reference is automatically generated from the Oso Django library source files.
Connect with us on Slack
If you have any questions, or just want to talk something through, jump into Slack. An Oso engineer or one of the thousands of developers in the growing community will be happy to help.