Comments (11)
The following example demonstrates how to do an authentication without involving the UserModel. We use it to authenticate service related requests.
myapp/authentication.py
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
class AuthenticatedServiceClient:
def is_authenticated(self):
return True
class JwtServiceOnlyAuthentication(JSONWebTokenAuthentication):
def authenticate_credentials(self, payload):
# Assign properties from payload to the AuthenticatedServiceClient object if necessary
return AuthenticatedServiceClient()
myapp/settings.py
REST_FRAMEWORK = {
'UNAUTHENTICATED_USER': None,
'DEFAULT_AUTHENTICATION_CLASSES': (
'myapp.authentication.JwtServiceOnlyAuthentication',
),
}
request.user
will then contain the AuthenticatedServiceClient
object.
from django-rest-framework-jwt.
@mgonto totally, you'd need to build your own authentication backend.
from django-rest-framework-jwt.
@jpadilla do you have a link to something I can read to find out about this? I'm a DJango n00b sorry :D.
Thanks!
from django-rest-framework-jwt.
from django-rest-framework-jwt.
So I should fork your project, change that code and then use my fork, right?
If that's the case, thanks and close the issue :)
from django-rest-framework-jwt.
You could define your own or subclass this one from code base. Be sure to update Django REST Framework's DEFAULT_AUTHENTICATION_CLASSES to contain your module.
from django-rest-framework-jwt.
Ohh understood.
Thanks for the info :).
Martin Gontovnikas
Software Engineer
Buenos Aires, Argentina
Twitter: @mgonto (https://twitter.com/mgonto)
Linkedin: http://www.linkedin.com/in/mgonto
Github: https://github.com/mgonto
On Friday, 13 de June de 2014 at 17:48, José Padilla wrote:
You could define your own or subclass this one from code base. Be sure to update Django REST Framework's DEFAULT_AUTHENTICATION_CLASSES to contain your module.
—
Reply to this email directly or view it on GitHub (#22 (comment)).
from django-rest-framework-jwt.
@mgonto No problem
from django-rest-framework-jwt.
Hey Guys,
We have been using drf-jwt for a while now. I added some customization by to avoid concurrent logins. Now our use case requires us to use JWT with payload as secretKey and nothing to do with user model in addition to the previous running authentication mechanism. I tried to follow @Schweigi 's approach but what was happening was when I tried to generate a token it was asking me to fill out the username and password. Btw these secretKeys are saved in database. Disassociating UserModel from payload could open up drf-jwt for lot of other cases.
from rest_framework_jwt.serializers import *
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
def jwt_payload_handler_secret_based(token):
"""
Updated jwt payload handler to add last login unix timestamp for token/user-less in payload.
"""
warnings.warn(
'The following fields will be removed in the future: '
'`email` and `user_id`. ',
DeprecationWarning
)
payload = {
'token': token,
'exp': datetime.utcnow() + api_settings.JWT_EXPIRATION_DELTA,
'jwt_indee_verification_id': str(token.last_login.timestamp())
}
# Include original issued at time for a brand new token,
# to allow token refresh
if api_settings.JWT_ALLOW_REFRESH:
payload['orig_iat'] = timegm(
datetime.utcnow().utctimetuple()
)
if api_settings.JWT_AUDIENCE is not None:
payload['aud'] = api_settings.JWT_AUDIENCE
if api_settings.JWT_ISSUER is not None:
payload['iss'] = api_settings.JWT_ISSUER
return payload
class ServiceOnlyJSONWebTokenSerializer(JSONWebTokenSerializer):
"""
Serializer class used to validate a token.
Returns a JSON Web Token that can be used to authenticate later calls.
"""
def __init__(self, *args, **kwargs):
"""
Dynamically add the USERNAME_FIELD to self.fields.
"""
super(JSONWebTokenSerializer, self).__init__(*args, **kwargs)
self.fields['tdvalue'] = serializers.IntegerField(required=False)
self.fields['jwt_indee_service_id'] = serializers.CharField(required=True)
def validate(self, attrs):
credentials = {
self.username_field: attrs.get(self.username_field),
'password': attrs.get('password')
}
try:
fycTokenObj = FycToken.objects.get(
token_key=attrs.get('jwt_indee_service_id')
)
except Exception as fyctoken_fetch_error:
msg = _(
'Some error occured while logging in.')
raise serializers.ValidationError(msg)
if all(credentials.values()):
if fycTokenObj:
if not fycTokenObj.active:
msg = _('Token is disabled.')
raise serializers.ValidationError(msg)
tmp_exp = api_settings.JWT_EXPIRATION_DELTA
if attrs.get('tdvalue') is not None:
api_settings.JWT_EXPIRATION_DELTA = timedelta(
seconds=attrs.get('tdvalue'))
# save the login time stamp
fycTokenObj.last_login = datetime.now()
fycTokenObj.save()
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
payload = jwt_payload_handler_secret_based(fycTokenObj.token_key)
return {
'token': jwt_encode_handler(payload),
'user': fycTokenObj
}
else:
msg = _('Unable to log in with provided credentials. Pappa')
raise serializers.ValidationError(msg)
else:
msg = _('Must include "jwt_indee_service_id".')
raise serializers.ValidationError(msg)
class ServiceOnlyJSONWebTokenAuthentication(JSONWebTokenAuthentication):
"""
Overriding the default JSONWebTokenAuthentication to accomodate tokens for apps.
https://github.com/GetBlimp/django-rest-framework-jwt/issues/22#issuecomment-166451133
https://www.django-rest-framework.org/api-guide/authentication/
"""
def authenticate_credentials(self, payload):
"""
Returns an active user that matches the payload's user id and email.
"""
jwt_indee_service_id = jwt_get_indee_service_id_from_payload(payload)
jwt_indee_verification_id = jwt_get_indee_ll_id_from_payload(payload)
if not jwt_indee_service_id:
msg = _('Invalid Token.')
raise exceptions.AuthenticationFailed(msg)
try:
fycTokenObj = FycToken.objects.get(token_id = jwt_indee_service_id)
except User.DoesNotExist:
msg = _("Couldn't find the Token. Please reach out to [email protected]")
raise exceptions.AuthenticationFailed(msg)
if not fycTokenObj.active:
msg = _('Token has been disabled by the sender.')
raise exceptions.AuthenticationFailed(msg)
if fycTokenObj.expiry_date < timezone.now() :
msg = _('Token has expired.')
raise exceptions.AuthenticationFailed(msg)
if jwt_indee_verification_id != str(fycTokenObj.last_login.timestamp()):
msg = _('This login was overriden, concurrent logins are not allowed.')
raise exceptions.AuthenticationFailed(msg)
return AuthenticatedServiceClient()
In the urls.py I have
from rest_framework_jwt.views import ObtainJSONWebToken
urlpatterns += patterns('',
url(r'^api-token-auth/test/', ObtainJSONWebToken.as_view(
serializer_class=ServiceOnlyJSONWebTokenSerializer)),
)
When I try and generate the token I see this error:
Could anyone provide some pointers on this? Thanks. I also checked #349 and #145 but wasn't able to figure this out. Thanks
from django-rest-framework-jwt.
@Aameer You can just use PyJWT library for signing and decoding custom tokens. Alternatively, Django has built-in functionality for signing strings and tokens:
https://docs.djangoproject.com/en/2.1/topics/signing/
from django-rest-framework-jwt.
@Alex3917 Thanks for you comment. What I ended up doing is mentioned as under. This made sure my current system with drf-jwt is working as expected and I have this parallel system which uses secrets alone as authentication mechanism and re-uses many of the things used by drf-jwt. Would have loved to see something like this in built with drf-jwt, where we could even decouple users.
URLS
from apps.myapps.api_views import FycTokenGenrator
urlpatterns += patterns('',
url(r'^loginWithSecret/',
FycTokenGenrator.as_view(),
name='fyc-token'),
)
VIEWS
from rest_framework import permissions, status, generics
from apps.mytokenapp.models import FycToken
from apps.mytokenapp.serializers import FycTokenSerializerOpen
from apps.myapps.utils import CustomJSONWebTokenAuthentication,\
ServiceOnlyJSONWebTokenAuthentication, jwt_payload_handler_token_based,
get_encoded_jwt
class FycTokenGenrator(generics.RetrieveUpdateDestroyAPIView):
"""
API Endpoint to get the secret from user and reply with jwt token.
For now added same auth over it to test.
"""
authentication_classes = (ServiceOnlyJSONWebTokenAuthentication,)
permission_classes = (permissions.AllowAny,)
serializer_class = FycTokenSerializerOpen
def get_permissions(self):
"""
Override the permissions for POST
"""
if self.request.method == 'POST':
self.permission_classes = (permissions.AllowAny,)
return super(FycTokenGenrator, self).get_permissions()
def get(self, request):
return Response({'message': "GET method not allowed"},
status=status.HTTP_405_METHOD_NOT_ALLOWED)
def post(self, request):
try:
token_key = request.data.get('jwt_service_id', None)
if token_key:
try:
fycTokenObj = FycToken.objects.get(
fyctoken_key=token_key
)
except Exception as fyctoken_fetch_error:
msg = 'Some error occured while logging in.'
return Response({'message': msg},
status=status.HTTP_403_FORBIDDEN)
fycTokenObj.last_login = timezone.now()
fycTokenObj.save()
payload = jwt_payload_handler_token_based(fycTokenObj)
encoded_jwt = get_encoded_jwt(payload)
return Response(
{'token': encoded_jwt}, status=status.HTTP_200_OK)
else:
msg = 'Some error occured while logging in.'
return Response({'message': msg},status=status.HTTP_403_FORBIDDEN)
except Exception as post_fyc_token_generator_error:
message = "Some error occured while logging in"
return Response({
"message": str(message)},
status=status.HTTP_500_INTERNAL_SERVER_ERROR)
def put(self, request):
return Response({'message': "Put method not allowed"},
status=status.HTTP_405_METHOD_NOT_ALLOWED)
def patch(self, request):
return Response({'message': "Patch method not allowed"},
status=status.HTTP_405_METHOD_NOT_ALLOWED)
def delete(self, request):
return Response({'message': "Delete method not allowed"},
status=status.HTTP_405_METHOD_NOT_ALLOWED)
AuthMiddleWare
import jwt
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
def jwt_payload_handler_token_based(tokenObj):
"""
Updated jwt payload handler to add last login unix timestamp
for token/user-less in payload.
"""
warnings.warn(
'The following fields will be removed in the future: '
'`email` and `user_id`. ',
DeprecationWarning
)
payload = {
'jwt_service_id': tokenObj.fyctoken_key,
'exp': datetime.utcnow() + api_settings.JWT_EXPIRATION_DELTA,
'jwt_verification_id': str(tokenObj.last_login.timestamp())
}
# Include original issued at time for a brand new token,
# to allow token refresh
if api_settings.JWT_ALLOW_REFRESH:
payload['orig_iat'] = timegm(
datetime.utcnow().utctimetuple()
)
if api_settings.JWT_AUDIENCE is not None:
payload['aud'] = api_settings.JWT_AUDIENCE
if api_settings.JWT_ISSUER is not None:
payload['iss'] = api_settings.JWT_ISSUER
print(payload)
return payload
def get_encoded_jwt(payload):
encoded_jwt = jwt.encode(
payload,
settings.SECRET_KEY,
algorithm='HS256'
)
return encoded_jwt
class AuthenticatedServiceClient(object):
def is_authenticated(self, fycTokenObj=None):
"""
Always return True. This is a way to tell if the token has been
authenticated
"""
return True
def __init__(self,fycTokenObj=None):
"""
This will assign a large enough id for the with secret only user/service so that it doesn't
clash with actual Users' model. (any suggestions to improve this portion are welcome!)
"""
total_users_supported_without_clashing_throttle = 999999999
self.pk = total_users_supported_without_clashing_throttle + fycTokenObj.id #model id which has secrets
def jwt_get_ll_id_from_payload(payload):
"""
Gets the last login unix time stamp from the payload
"""
return payload.get('jwt_verification_id', None)
def jwt_get_service_id_from_payload(payload):
"""
Gets the service id payload
"""
return payload.get('jwt_service_id', None)
# TOKEN MIDDLE WARE
class ServiceOnlyJSONWebTokenAuthentication(JSONWebTokenAuthentication):
"""
Overriding the default JSONWebTokenAuthentication to accomodate tokens for apps.
https://github.com/GetBlimp/django-rest-framework-jwt/issues/22#issuecomment-166451133
https://www.django-rest-framework.org/api-guide/authentication/
"""
def authenticate_credentials(self, payload):
"""
Returns an active user that matches the payload's user id and email.
"""
jwt_service_id = jwt_get_service_id_from_payload(payload)
jwt_verification_id = jwt_get_ll_id_from_payload(payload)
if not jwt_service_id:
msg = _('Invalid Token.')
raise exceptions.AuthenticationFailed(msg)
try:
# from model which has the secret
fycTokenObj = FycToken.objects.get(fyctoken_key = jwt_service_id)
except Exception as fycTokenObjDoesNotExistError:
msg = _("Couldn't find the Token.")
raise exceptions.AuthenticationFailed(msg)
if not fycTokenObj.active:
msg = _('Token has been disabled by the sender.')
raise exceptions.AuthenticationFailed(msg)
if fycTokenObj.expiry_date < timezone.now() :
msg = _('Token has expired.')
raise exceptions.AuthenticationFailed(msg)
if jwt_verification_id != str(fycTokenObj.last_login.timestamp()):
msg = _('This login was overriden, concurrent logins are not allowed.')
raise exceptions.AuthenticationFailed(msg)
return AuthenticatedServiceClient(fycTokenObj)
from django-rest-framework-jwt.
Related Issues (20)
- Is there a way that we can avoid multiple token generations for a single user if he/she try to login on different browsers? HOT 2
- JSONWebTokenAuthentication object has no attribute 'media_type'
- external server
- Call an endpoint without Authorization header HOT 1
- Add support for ES256 signing algorithm
- [feature] permit to use custom header instead of `Authorization`
- registration
- how to refresh existing tokens??? HOT 6
- redis cache HOT 1
- WinError 123 after tutorial HOT 1
- How to use this library by only using Http Only Cookie? HOT 1
- Curious Whether JWT Still Works Given Libraries Requirements Mismatch? HOT 3
- Status HOT 12
- Documentation not found HOT 2
- Dead Link in readme.md HOT 1
- DeprecationWarning: The following fields will be removed in the future: `email` and `user_id`. HOT 1
- Hope to support the response format of custom authentication failure HOT 1
- Unreachable code when user is_active is False in. HOT 1
- Can we use allauth only for the things, where we can get involved with email verification, and jwt for others purposes like login/get api request/ post api requests....????
- Cookie not removed in request when response is 401
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from django-rest-framework-jwt.