-
-
Notifications
You must be signed in to change notification settings - Fork 6.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
TokenAuthentication: Allow custom keyword in the header #4097
Conversation
Current coverage is 91.39%@@ master #4097 diff @@
==========================================
Files 51 51
Lines 5472 5473 +1
Methods 0 0
Messages 0 0
Branches 0 0
==========================================
+ Hits 5001 5002 +1
Misses 471 471
Partials 0 0
|
6360db2
to
a4c8e56
Compare
This isn't unreasonable, but I'd still rather just have end-users customize the class if they want differing behavior. |
I don't understand the objection against this, so I'll try to explain my reason even further. This is the customization I would like to be able to do (In my own code/project/app) and this pull request makes that possible: from rest_framework import authentication
class BearerAuthentication(authentication.TokenAuthentication):
'''
Simple token based authentication using utvsapitoken.
Clients should authenticate by passing the token key in the 'Authorization'
HTTP header, prepended with the string 'Bearer '. For example:
Authorization: Bearer 956e252a-513c-48c5-92dd-bfddc364e812
'''
keyword = 'Bearer' Unfortunately, this is what has to be done at this point (without this pull request): from rest_framework import authentication, exceptions
from django.utils.translation import ugettext_lazy as _
class BearerAuthentication(authentication.TokenAuthentication):
'''
Simple token based authentication using utvsapitoken.
Clients should authenticate by passing the token key in the 'Authorization'
HTTP header, prepended with the string 'Bearer '. For example:
Authorization: Bearer 956e252a-513c-48c5-92dd-bfddc364e812
'''
def authenticate(self, request):
auth = authentication.get_authorization_header(request).split()
if not auth or auth[0].lower() != b'bearer':
return None
if len(auth) == 1:
msg = _('Invalid token header. No credentials provided.')
raise exceptions.AuthenticationFailed(msg)
elif len(auth) > 2:
msg = _('Invalid token header. Token string should not contain spaces.')
raise exceptions.AuthenticationFailed(msg)
try:
token = auth[1].decode()
except UnicodeError:
msg = _('Invalid token header. Token string should not contain invalid characters.')
raise exceptions.AuthenticationFailed(msg)
return self.authenticate_credentials(token)
def authenticate_header(self, request):
return 'Bearer' This is no customization, this is copy pasting code form Django REST framework. This PR simply allows easier customization. Would you please reconsider, or provide more verbose explanation? I'm willing to shape this PR a bit (make |
I'd join in this request on the principle. |
@@ -150,6 +150,7 @@ class TokenAuthentication(BaseAuthentication): | |||
Authorization: Token 401f7ac837da42b97f613d789819ff93537bee6a | |||
""" | |||
|
|||
keyword = 'token' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd suggest we use the proper casing here, and instead do .lower()
in the comparison against the auth header.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I was considering that as well, don't have strong opinion. Will do.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
Given @xordoquy's take let's reopen and have this in.
In the absence of any other factors the tendency is always for classes such as this to accumulate more and more interface. I'm generally in favor of pushing back against that with "put some code in your codebase" wherever possible. |
This allows subclassing TokenAuthentication and setting custom keyword, thus allowing the Authorization header to be for example: Bearer 956e252a-513c-48c5-92dd-bfddc364e812 It doesn't change the behavior of TokenAuthentication itself, it simply allows to reuse the logic of TokenAuthentication without the need of copy pasting the class and changing one hardcoded string. Related: encode#4080
I can see. Well, I'm replacing the token validation with my own logic, so I'm definitely putting some code in my own codebase, I was simply against copy pasting the parts that should be inheritable. |
👍 S'all good. Thanks @hroncok, @xordoquy, @jpocentek. |
Thanks @xordoquy, @tomchristie.
|
Thanks @tomchristie for taking the time to reconsider this and thanks @hroncok for the PR. |
I'm a bit late on the conv, but I don't really think |
Honestly, I made up the variable name. Didn't think of anything better. In
this context it's a word, not a scheme.
But I don't mind any other reasonable name.
|
You are quite right. Shall I craft another PR? |
This allows subclassing TokenAuthentication and setting custom keyword,
thus allowing the Authorization header to be for example:
It doesn't change the behavior of TokenAuthentication itself,
it simply allows to reuse the logic of TokenAuthentication without
the need of copy pasting the class and changing one hardcoded string.
Related: #4080