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

jwt_payload_handler needs request? #308

Open
n1ncha opened this issue Feb 21, 2017 · 3 comments
Open

jwt_payload_handler needs request? #308

n1ncha opened this issue Feb 21, 2017 · 3 comments

Comments

@n1ncha
Copy link

n1ncha commented Feb 21, 2017

I'm working on a django project that will support multiple sites, therefore the payload of my token will be different depending on what the domain of the request is (I'm using the RequestSite methodology rather than SITE_ID). Is there a way to get the request object into the jwt_payload_handler that doesn't require passing it as a parameter? I don't see an obvious way, but I don't want to rewrite the source if there's a recommended way. Thanks.

@alexmason528
Copy link

alexmason528 commented May 16, 2017

You should override ObtainJSONWebToken view and ObtainJSONWebToken serializer.
And then in your customized ObtainJSONWebToken serializer, add request parameter in the jwt_payload_handler function.

// urls.py
urlpatterns = [
url(r'^api-token-auth/', custom_obtain_jwt_token),
url(r'^api-token-refresh/', refresh_jwt_token),
url(r'^api-token-verify/', verify_jwt_token),
];

//views.py
class CustomObtainJSONWebToken(JSONWebTokenAPIView):
serializer_class = CustomJSONWebTokenSerializer

//serializers.py
class CustomJSONWebTokenSerializer(Serializer):
def init(self, *args, **kwargs):
super(CustomJSONWebTokenSerializer, self).init(*args, **kwargs)
self.fields[self.username_field] = serializers.CharField()
self.fields['password'] = PasswordField(write_only=True)
print(self.context['request'])
@Property
def username_field(self):
return get_username_field()

def validate(self, attrs):
    credentials = {
        self.username_field: attrs.get(self.username_field),
        'password': attrs.get('password')
    }

    if all(credentials.values()):
        user = authenticate(**credentials)

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

            payload = jwt_payload_handler(user, self.context['request'])

            return {
                'token': jwt_encode_handler(payload),
                'user': user
            }
        else:
            msg = _('Unable to log in with provided credentials.')
            raise serializers.ValidationError(msg)
    else:
        msg = _('Must include "{username_field}" and "password".')
        msg = msg.format(username_field=self.username_field)
        raise serializers.ValidationError(msg)

//utils.py
def customized_payload_handler(user, request):
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,
    'username': username,
    'exp': datetime.utcnow() + api_settings.JWT_EXPIRATION_DELTA
}
if hasattr(user, 'email'):
    payload['email'] = user.email
if isinstance(user.pk, uuid.UUID):
    payload['user_id'] = str(user.pk)

payload[username_field] = username

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

//settings.py
JWT_AUTH = {
'JWT_ENCODE_HANDLER':
'your_module.utils.encode_handler',

'JWT_DECODE_HANDLER':
'your_module.utils.decode_handler',

'JWT_PAYLOAD_HANDLER':
'your_module.utils.customized_payload_handler',

'JWT_PAYLOAD_GET_USER_ID_HANDLER':
'rest_framework_jwt.utils.jwt_get_user_id_from_payload_handler',

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

'JWT_GET_USER_SECRET_KEY': None,
'JWT_PUBLIC_KEY': None,
'JWT_PRIVATE_KEY': None,
'JWT_ALGORITHM': 'HS256',
'JWT_VERIFY': True,
'JWT_VERIFY_EXPIRATION': True,
'JWT_LEEWAY': 0,
'JWT_EXPIRATION_DELTA': datetime.timedelta(seconds=300),
'JWT_AUDIENCE': None,
'JWT_ISSUER': None,

'JWT_ALLOW_REFRESH': True,
'JWT_REFRESH_EXPIRATION_DELTA': datetime.timedelta(days=7),

'JWT_AUTH_HEADER_PREFIX': 'JWT',
'JWT_AUTH_COOKIE': None,

}

@decibyte
Copy link

decibyte commented Aug 7, 2019

Passing the request as a second argument (after the user) to the payload handler would avoid all these overridings.

@jpadilla, do you have compelling arguments against doing that, other than backwards compatibility? It would be extremely handy, and I can think of lot's of other cases for it (in my case: Optionally add data to the payload, based on POST data).

@string-areeb
Copy link

#484 The project is not maintained. Use https://github.com/Styria-Digital/django-rest-framework-jwt or https://github.com/davesque/django-rest-framework-simplejwt

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants