django-rest-framework-jwt icon indicating copy to clipboard operation
django-rest-framework-jwt copied to clipboard

jwt_payload_handler needs request?

Open n1ncha opened this issue 8 years ago • 3 comments

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.

n1ncha avatar Feb 21 '17 19:02 n1ncha

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,

}

alexmason528 avatar May 16 '17 02:05 alexmason528

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).

decibyte avatar Aug 07 '19 18:08 decibyte

#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

string-areeb avatar Aug 08 '19 13:08 string-areeb