Skip to content
This repository has been archived by the owner on May 26, 2020. It is now read-only.

Commit

Permalink
Use username instead of user_id
Browse files Browse the repository at this point in the history
- Add DeprecationWarnings
- Use get_by_natural_key to fetch User
- Add JWT_PAYLOAD_GET_USERNAME_HANDLER
  • Loading branch information
jpadilla committed Jul 26, 2015
1 parent aeee6d4 commit a3b4d44
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 23 deletions.
24 changes: 14 additions & 10 deletions rest_framework_jwt/authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

User = get_user_model()
jwt_decode_handler = api_settings.JWT_DECODE_HANDLER
jwt_get_user_id_from_payload = api_settings.JWT_PAYLOAD_GET_USER_ID_HANDLER
jwt_get_username_from_payload = api_settings.JWT_PAYLOAD_GET_USERNAME_HANDLER


class BaseJSONWebTokenAuthentication(BaseAuthentication):
Expand Down Expand Up @@ -48,18 +48,22 @@ def authenticate_credentials(self, payload):
"""
Returns an active user that matches the payload's user id and email.
"""
user_id = jwt_get_user_id_from_payload(payload)

if user_id is not None:
try:
user = User.objects.get(pk=user_id, is_active=True)
except User.DoesNotExist:
msg = _('Invalid signature.')
raise exceptions.AuthenticationFailed(msg)
else:
username = jwt_get_username_from_payload(payload)

if not username:
msg = _('Invalid payload.')
raise exceptions.AuthenticationFailed(msg)

try:
user = User.objects.get_by_natural_key(username)
except User.DoesNotExist:
msg = _('Invalid signature.')
raise exceptions.AuthenticationFailed(msg)

if not user.is_active:
msg = _('User account is disabled.')
raise exceptions.AuthenticationFailed(msg)

return user


Expand Down
22 changes: 13 additions & 9 deletions rest_framework_jwt/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
jwt_decode_handler = api_settings.JWT_DECODE_HANDLER
jwt_get_user_id_from_payload = api_settings.JWT_PAYLOAD_GET_USER_ID_HANDLER
jwt_get_username_from_payload = api_settings.JWT_PAYLOAD_GET_USERNAME_HANDLER


class JSONWebTokenSerializer(Serializer):
Expand Down Expand Up @@ -103,19 +103,23 @@ def _check_payload(self, token):
return payload

def _check_user(self, payload):
# Make sure user exists (may want to refactor this)
try:
user_id = jwt_get_user_id_from_payload(payload)
username = jwt_get_username_from_payload(payload)

if user_id is not None:
user = User.objects.get(pk=user_id, is_active=True)
else:
msg = _('Invalid payload.')
raise serializers.ValidationError(msg)
if not username:
msg = _('Invalid payload.')
raise serializers.ValidationError(msg)

# Make sure user exists
try:
user = User.objects.get_by_natural_key(username)
except User.DoesNotExist:
msg = _("User doesn't exist.")
raise serializers.ValidationError(msg)

if not user.is_active:
msg = _('User account is disabled.')
raise serializers.ValidationError(msg)

return user


Expand Down
4 changes: 4 additions & 0 deletions rest_framework_jwt/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
'JWT_PAYLOAD_GET_USER_ID_HANDLER':
'rest_framework_jwt.utils.jwt_get_user_id_from_payload_handler',

'JWT_PAYLOAD_GET_USERNAME_HANDLER':
'rest_framework_jwt.utils.jwt_get_username_from_payload_handler',

'JWT_RESPONSE_PAYLOAD_HANDLER':
'rest_framework_jwt.utils.jwt_response_payload_handler',

Expand All @@ -43,6 +46,7 @@
'JWT_DECODE_HANDLER',
'JWT_PAYLOAD_HANDLER',
'JWT_PAYLOAD_GET_USER_ID_HANDLER',
'JWT_PAYLOAD_GET_USERNAME_HANDLER',
'JWT_RESPONSE_PAYLOAD_HANDLER',
)

Expand Down
38 changes: 34 additions & 4 deletions rest_framework_jwt/utils.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,37 @@
import jwt

import warnings
from calendar import timegm
from datetime import datetime

from rest_framework_jwt.compat import get_username, get_username_field
from rest_framework_jwt.settings import api_settings


def jwt_payload_handler(user):
username_field = get_username_field()
username = get_username(user)

warnings.warn(
'The following fields will be removed in the future: '
'`email` and `user_id`. ',
DeprecationWarning
)

payload = {
'user_id': user.pk,
'email': user.email,
'username': username,
'exp': datetime.utcnow() + api_settings.JWT_EXPIRATION_DELTA
}

payload[get_username_field()] = get_username(user)
payload[username_field] = username

# 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()
)

return payload

Expand All @@ -22,8 +40,20 @@ def jwt_get_user_id_from_payload_handler(payload):
"""
Override this function if user_id is formatted differently in payload
"""
user_id = payload.get('user_id')
return user_id
warnings.warn(
'The following will be removed in the future. '
'Use `JWT_PAYLOAD_GET_USERNAME_HANDLER` instead.',
DeprecationWarning
)

return payload.get('user_id')


def jwt_get_username_from_payload_handler(payload):
"""
Override this function if username is formatted differently in payload
"""
return payload.get('username')


def jwt_encode_handler(payload):
Expand Down
3 changes: 3 additions & 0 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import json
import base64
import pytest

import jwt.exceptions
from django.test import TestCase
Expand Down Expand Up @@ -29,6 +30,8 @@ def setUp(self):
def test_jwt_payload_handler(self):
payload = utils.jwt_payload_handler(self.user)

pytest.deprecated_call(utils.jwt_payload_handler, self.user)

self.assertTrue(isinstance(payload, dict))
self.assertEqual(payload['user_id'], self.user.pk)
self.assertEqual(payload['email'], self.email)
Expand Down

0 comments on commit a3b4d44

Please sign in to comment.