How to Implement Multiple(Custom) Authentication in Django Rest Framework
Problem
You might use multiple authentication scheme in DRF, for meeting your requirements such as Session, Token, Basic(username and password) Authentication etc.. However it is not that simple to use multiple authentications, because it is not applied for your every APIs, It is changing belong to your type of response.
Although multiple authentication schemes may be in use, only one scheme may be used to determine the type of response. - DRF docs
But In many cases, you want to use those authentication classes in a single request(somebody will say it is not a good practice). That means that you should write your own custom Authentication class.
When I need to use custom Authentication?
- I want to mix it up in a single Authentication class!
- Fine, but you should keep the type of your request/response.
- Or you can check the types in your custom class.
- For example, you want to check Sessions and then Token Authentications.
I have to classify the tokens per users, and also devices! (or anything)
- You might have requirements to classify several type of tokens.
- The TokenAuthentication provided by DRF uses only one type of token. (per users)
- You can compose with the checking the Bearer Token first and then User Tokens.
I have my Special authentication Ideas.
- As your wish.
- For example, you can use your special HTTP Headers, Designated IP Address.
What I have to do
- You need to define your custom authentication class inherited DRF's authentication class.
- After authentication, return Tuple with the results (user, auth). If authentication failed, raise exception error.
- Set default Authentication class in settings.py or implement per api view(viewsets)
#myapp/auth.py
from django.contrib.auth.models import User
from rest_framework import authentication
from rest_framework import exceptions
class ExampleAuthentication(authentication.BaseAuthentication):
def authenticate(self, request):
try:
# some authentication logic
except :
raise exceptions.AuthenticationFailed('AUTH FAILED')
return (user, None)
#settings.py
AUTHENTICATION_BACKENDS = (
'myapp.auth.ExampleAuthentication',
)
Examples
I will give you s simple examples, might help.
Implement multiple authentications.
class ExampleAuthentication(authentication.BaseAuthentication):
def authenticate(self, request):
try:
#BasicAuthentication
try:
return authentication.BasicAuthentcation.authenticate(request)
except:
#RemoteUserAuthentication
try:
return authenticatiohn.RemoteUserAuthentication.authenticate(request)
except:
raise exceptions.AuthenticationFailed('AUTH FAILED')
except :
raise exceptions.AuthenticationFailed('AUTH FAILED')
Several Type of Tokens
class ExampleAuthentication(authentication.BaseAuthentication):
def authenticate(self, request):
try:
api_key = request.META.get('HTTP_X_API_KEY')
#custom bearer token
if api_key in [YOUR_API_KEYS]:
return (user, None)
#token in your DB
elif Token.objects.filter(token=api_key):
return (Token.objects.get(token=api_key).user, None)
else:
raise exceptions.AuthenticationFailed('AUTH FAILED')
except :
raise exceptions.AuthenticationFailed('AUTH FAILED')
Designated IP Address
class ExampleAuthentication(authentication.BaseAuthentication):
def get_client_ip(self, request):
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
if x_forwarded_for:
ip = x_forwarded_for.split(',')[0]
else:
ip = request.META.get('REMOTE_ADDR')
return ip
def authenticate(self, request):
try:
ip = self.get_client_ip(request)
user = DesignatedIPAddress.objects.get(ip=ip).user
return (user, None)
except:
raise exceptions.AuthenticationFailed('AUTH FAILED')
Conclusion
It was just simple authentication examples to fit your needs. And also I strongly recommend to implement your own Oauth2 auth server, and forget all the 'custom authentications' someday. But It will help you right away. So if you have any questions, reply me. Thanks