问题
In an API built with Django REST Framework authentication can be done using the TokenAuthentication method. Its documentation says the authentication token should be sent via an Authorization
header.
Often one can send API-keys or tokens via a query string in order to authenticate, like https://domain.com/v1/resource?api-key=lala
.
Is there a way to do the same with Django REST Framework's TokenAuthentication?
回答1:
By deafult DRF doesn't support query string to authenticate, but you can easily override their authenticate
method in TokenAuthentication
class to support it.
An example would be:
class TokenAuthSupportQueryString(TokenAuthentication):
"""
Extend the TokenAuthentication class to support querystring authentication
in the form of "http://www.example.com/?auth_token=<token_key>"
"""
def authenticate(self, request):
# Check if 'token_auth' is in the request query params.
# Give precedence to 'Authorization' header.
if 'auth_token' in request.QUERY_PARAMS and \
'HTTP_AUTHORIZATION' not in request.META:
return self.authenticate_credentials(request.QUERY_PARAMS.get('auth_token'))
else:
return super(TokenAuthSupportQueryString, self).authenticate(request)
回答2:
class QueryStringBasedTokenAuthentication(TokenAuthentication):
def authenticate(self, request):
key = request.query_params.get('auth_token').strip()
if key:
return self.authenticate_credentials(key)
return False
DRF
has TokenAuthentication
which looks for token
in header
. The method authenticate_credentials
takes care verifying the token.
回答3:
As of 2018 using Django Rest Framework you can create your own Authentication class see http://getblimp.github.io/django-rest-framework-jwt/#extending-jsonwebtokenauthentication
class JSONWebTokenAuthenticationQS(BaseJSONWebTokenAuthentication):
def get_jwt_value(self, request):
return request.QUERY_PARAMS.get('jwt')
Then in the APIView class add
authentication_classes = (JSONWebTokenAuthenticationQS,)
Or
@authentication_classes((JSONWebTokenAuthenticationQS,))
On the view function.
回答4:
Following up on Scott Warren's answer. That was a step in the right direction, because the DRFJWT docs don't include the important authentication_classes line. But with that, as noted in Issue 441 there is a big problem that you can't mix the JWT authentication methods. I ended up with:
class JSONWebTokenAuthenticationQS(JSONWebTokenAuthentication):
def get_jwt_value(self, request):
return request.GET.get('jwt') or JSONWebTokenAuthentication.get_jwt_value(self, request)
which so far seems to work well. It uses JSONWebTokenAuthentication instead of the Base class, because it has to in order to use the original get_jwt_value method.
回答5:
refer answer of OmriToptix
and Scott Warren
and others website 1 and 2
for now most case use JSONWebTokenAuthentication
, so now should override its get_jwt_value
, full code is:
# from rest_framework_jwt.authentication import BaseJSONWebTokenAuthentication
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from rest_framework.authentication import get_authorization_header
class JWTAuthByQueryStringOrHeader(JSONWebTokenAuthentication):
# class JWTAuthByQueryStringOrHeader(BaseJSONWebTokenAuthentication):
"""
Extend the TokenAuthentication class to support querystring authentication
in the form of "http://www.example.com/?jwt_token=<token_key>"
"""
def get_jwt_value(self, request):
# Check if 'jwt_token' is in the request query params.
# Give precedence to 'Authorization' header.
queryParams = request.query_params
reqMeta = request.META
if ('jwt_token' in queryParams) and ('HTTP_AUTHORIZATION' not in reqMeta):
jwt_token = queryParams.get('jwt_token')
# got jwt token from query parameter
return jwt_token
else:
# call JSONWebTokenAuthentication's get_jwt_value
# to get jwt token from header of 'Authorization'
return super(JWTAuthByQueryStringOrHeader, self).get_jwt_value(request)
here save above code to apps/util/jwt_token.py
, then NOT FORGET add related Django
settings:
REST_FRAMEWORK = {
...
'DEFAULT_AUTHENTICATION_CLASSES': (
# 'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
'apps.util.jwt_token.JWTAuthByQueryStringOrHeader',
...
),
...
}
now frontend/web side can call api like this:
http://localhost:65000/api/v1/scripts/3d9e77b0-e538-49b8-8790-60301ca79e1d/script_word_export/?jwt_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiMWVkMGEwZDgtMmFiYi00MDFkLTk5NTYtMTQ5MzcxNDIwMGUzIiwidXNlcm5hbWUiOiJsc2R2aW5jZW50IiwiZXhwIjoxNTMxOTAyOTU0LCJlbWFpbCI6InZpbmNlbnQuY2hlbkBuYXR1cmxpbmcuY29tIn0.wheM7Fmv8y8ysz0pp-yUHFqfk-IQ5a8n_8OplbYkj7s
to pass jwt_token
into server side, get authorized to download/export the file.
while still support original method pass jwt token inside header 'Authorization'
:
POST http://localhost:65000/api/v1/scripts/3d9e77b0-e538-49b8-8790-60301ca79e1d/script_word_export/
Authorization: JWT eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiMWVkMGEwZDgtMmFiYi00MDFkLTk5NTYtMTQ5MzcxNDIwMGUzIiwidXNlcm5hbWUiOiJsc2R2aW5jZW50IiwiZXhwIjoxNTMxOTAyOTU0LCJlbWFpbCI6InZpbmNlbnQuY2hlbkBuYXR1cmxpbmcuY29tIn0.wheM7Fmv8y8ysz0pp-yUHFqfk-IQ5a8n_8OplbYkj7s
来源:https://stackoverflow.com/questions/29433416/token-in-query-string-with-django-rest-frameworks-tokenauthentication