I am trying to figure out the best way to implement token based authentication in my django app. An external, non-django application is setting a cookie, with a token, and I have a webservice that can retrieve user information based off of that token. If the user has the cookie set, they should not need to authenticate on my site and should be automatically logged in based on the info passed back by the web service. As I see it, there are a few different options to perform the actual check and I'm not sure which is best:
login_required
. LOGIN_REDIRECT_URL
page that will check/validate the cookie in an ajax call, and automatically redirect back to the referrer if the cookie authenticated.Is there an option I am missing? Ideally, there would be a way to build this into login_required
, without having to write a custom decorator.
JSON Web Token Authentication JSON Web Token is a fairly new standard which can be used for token-based authentication. Unlike the built-in TokenAuthentication scheme, JWT Authentication doesn't need to use a database to validate a token.
Token-based authentication is a protocol that generates encrypted security tokens. It enables users to verify their identity to websites, which then generates a unique encrypted authentication token.
You can get the token from the request. auth attribute. It returns a DRF Token instance. If you want only the key then you can access it with the request.
Before searching for code, be sure you read the documentation. http://docs.djangoproject.com/en/1.2/topics/auth/#other-authentication-sources Also read the supplied Django source.
You want to create three things.
Middleware to capture the token. This is where most of the work happens. It checks for the token, authenticates it (by confirming it with the identity manager) and then logs in the user.
Authentication backend to find Users. This is a stub. All it does is create users as needed. Your identity manager has the details. You're just caching the current version of the user on Django's local DB.
Here's the middleware (edited).
from django.contrib.auth import authenticate, login class CookieMiddleware( object ): """Authentication Middleware for OpenAM using a cookie with a token. Backend will get user. """ def process_request(self, request): if not hasattr(request, 'user'): raise ImproperlyConfigured() if "thecookiename" not in request.COOKIES: return token= request.COOKIES["thecookiename"] # REST request to OpenAM server for user attributes. token, attribute, role = identity_manager.get_attributes( token ) user = authenticate(remote_user=attribute['uid'][0]) request.user = user login(request, user)
The identity_manager.get_attributes
is a separate class we wrote to validate the token and get details on the user from the IM source. This, of course, has to be mocked for testing purposes.
Here's a backend (edited)
class Backend( RemoteUserBackend ): def authenticate(**credentials): """We could authenticate the token by checking with OpenAM Server. We don't do that here, instead we trust the middleware to do it. """ try: user= User.objects.get(username=credentials['remote_user']) except User.DoesNotExist: user= User.objects.create(username=credentials['remote_user'] ) # Here is a good place to map roles to Django Group instances or other features. return user
This does not materially change the decorators for authentication or authorization.
To make sure of this, we actually refresh the User and Group information from our identity manager.
Note that the middleware runs for every single request. Sometimes, it's okay to pass the token to the backed authenticate
method. If the token exists in the local user DB, the request can proceed without contacting the identity manager.
We, however, have complex rules and timeouts in the identity manager, so we have to examine every token to be sure it's valid. Once the middleware is sure the token is valid, we can then allow the backend to do any additional processing.
This isn't our live code (it's a little too complex to make a good example.)
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