向 DRF 简单 JWT 负载添加声明
Adding claims to DRF simple JWT payload
使用djangorestframework_simplejwt库,当POST到自定义视图
#urls.py
path('api/token/', MyTokenObtainPairView.as_view(), name='token_obtain'),
#views.py
class MyTokenObtainPairView(TokenObtainPairView):
serializer_class = MyTokenObtainPairSerializer
我能够获得以下访问令牌
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNTkwOTEwNjg0LCJqdGkiOiI3M2MxYmZkOWNmMGY0ZjI3OTY4MGY0ZjhlYjA1NDQ5NyIsInVzZXJfaWQiOjExfQ.5vs0LmNGseU6rtq3vuQyApupxhQM3FBAoKAq8MUukIBOOYfDAV9guuCVEYDoGgK6rdPSIq2mvcSxkILG8OH5LQ
通过转到 https://jwt.io/ 我可以看到有效载荷当前是
{
"token_type": "access",
"exp": 1590910684,
"jti": "73c1bfd9cf0f4f279680f4f8eb054497",
"user_id": 11
}
因此,我们可以看到令牌的第二部分是有效载荷 - 包含声明。
我浏览了 and now would like to know how to customize the Payload data by adding iat claim、用户名和今天的日期。
由于您已经为所需的视图 (MyTokenObtainPairView) 创建了一个子类,并为其相应的序列化程序 (MyTokenObtainPairSerializer) 创建了一个子类,因此将以下内容添加到序列化程序
class MyTokenObtainPairSerializer(TokenObtainPairSerializer):
...
@classmethod
def get_token(cls, user):
token = super().get_token(user)
# Add custom claims
token['iat'] = datetime.datetime.now()
token['user'] = user.username
token['date'] = str(datetime.date.today())
return token
然后,当您 POST 到达同一位置时,您将获得这样的访问令牌
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNTkwOTE0MTk4LCJqdGkiOiJhZDZmNzZhZjFmOGU0ZWJlOGI2Y2Y5YjQ4MGQzZjY2MiIsInVzZXJfaWQiOjExLCJpYXQiOjE1OTA5MTc0OTgsInVzZXIiOiJ0aWFnbyIsImRhdGUiOiIyMDIwLTA1LTMxIn0.-5U9P-WWmhlOenzCvc6b7_71Tz17LyNxe_DOMwwqH4RqrNsilVukEcZWFRGupLHRZjIvPya2QJGpiju9ujzQuw
使用 JWT,您可以看到相应的负载变化
{
"token_type": "access",
"exp": 1590914198,
"jti": "ad6f76af1f8e4ebe8b6cf9b480d3f662",
"user_id": 11,
"iat": 1590917498,
"user": "tiago",
"date": "2020-05-31"
}
在你的views.py
from rest_framework_simplejwt.tokens import RefreshToken
from rest_framework.response import Response
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import AllowAny
from decouple import config
from django.contrib.auth import authenticate
import jwt
@api_view(['POST'])
@permission_classes([AllowAny])
def get_tokens_for_user(request):
username = request.POST.get("username")
password = request.POST.get("password")
user = authenticate(username=username, password=password);
if user is not None:
refreshToken = RefreshToken.for_user(user)
accessToken = refreshToken.access_token
decodeJTW = jwt.decode(str(accessToken), config('SECRET_KEY'), algorithms=["HS256"]);
# add payload here!!
decodeJTW['iat'] = '1590917498'
decodeJTW['user'] = 'tiago'
decodeJTW['date'] = '2020-05-31'
#encode
encoded = jwt.encode(decodeJTW, config('SECRET_KEY'), algorithm="HS256")
return Response({
'status': True,
'refresh': str(refreshToken),
'access': str(encoded),
})
else:
return Response({
'status': False
})
# No backend authenticated the credentials
在你的urls.py
from django.urls import path, include
from .views import get_tokens_for_user
urlpatterns = [
path('login/', get_tokens_for_user, name="login"),
]
在你的settings.py
from pathlib import Path
from datetime import timedelta
from decouple import config
...
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = config('SECRET_KEY')
# Application definition
INSTALLED_APPS = [
...
# Rest
'rest_framework',
...
]
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework_simplejwt.authentication.JWTAuthentication',
],
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
]
}
# JWT
# https://django-rest-framework-simplejwt.readthedocs.io/en/latest/settings.html
SIMPLE_JWT = {
'ACCESS_TOKEN_LIFETIME': timedelta(minutes=60),
'REFRESH_TOKEN_LIFETIME': timedelta(days=1),
'AUTH_HEADER_TYPES': ('Bearer',),
'SIGNING_KEY': config('SECRET_KEY'),
'VERIFYING_KEY': config('SECRET_KEY'),
'ALGORITHM': 'HS256',
}
在你的根目录下添加
.env
SECRET_KEY = 'ep@4ojr4m!h73y2j(Whosebug)kra1*@tqel626wf@&p60)7u!6552+-'
运行时值
decodeJTW = {
'token_type': 'access',
'exp': 1612651527,
'jti': '7f415b28610348468ce74ec0f480fad1',
'user_id': 2,
'iat': '1590917498',
'user': 'tiago',
'date': '2020-05-31'
}
encode = {
"status":true,
"refresh":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTYxMjczNDU0NywianRpIjoiMDQ0MDI3ZTQzMTc2NDFiNDhhOGI2MjU4MjE4ZGZjNDkiLCJ1c2VyX2lkIjoyfQ.Qf0YfJLAmdYuavDHVng7Bwjmka551G6c1Gi4e-UdRuc",
"access":"b'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjEyNjUxNzQ3LCJqdGkiOiI2OWEzNjYwYjYxMTk0MzVjYjljZTA0OGQ3MmE1ODk1YSIsInVzZXJfaWQiOjIsImlhdCI6IjE1OTA5MTc0OTgiLCJ1c2VyIjoidGlhZ28iLCJkYXRlIjoiMjAyMC0wNS0zMSJ9.XUMvhL13zDZdbjYYPkYnwlZoHN6U7Zc3xUzXsKoVj2I'"
}
当我来到这里寻找一种解决方案,在使用 dj-rest-auth and djangorestframework_simplejwt I found a solution in the code 时将令牌过期添加到响应中(显然没有记录?):
有一个名为 JWT_AUTH_RETURN_EXPIRATION 的设置,如果设置为 True,则会将过期时间添加到响应中,如下所示:
{
"access_token": "ACCESS_TOKEN_STRING",
"refresh_token": "REFRESH_TOKEN_STRING",
"user": {
"pk": PK,
"email": "USER_EMAIL"
},
"access_token_expiration": "2021-02-10T10:40:46.883715Z",
"refresh_token_expiration": "2021-02-11T10:35:46.883728Z"
}
与刷新相同:
{
"access": "ACCESS_TOKEN_STRING",
"access_token_expiration": "2021-02-10T10:47:57.325545Z"
}
使用djangorestframework_simplejwt库,当POST到自定义视图
#urls.py
path('api/token/', MyTokenObtainPairView.as_view(), name='token_obtain'),
#views.py
class MyTokenObtainPairView(TokenObtainPairView):
serializer_class = MyTokenObtainPairSerializer
我能够获得以下访问令牌
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNTkwOTEwNjg0LCJqdGkiOiI3M2MxYmZkOWNmMGY0ZjI3OTY4MGY0ZjhlYjA1NDQ5NyIsInVzZXJfaWQiOjExfQ.5vs0LmNGseU6rtq3vuQyApupxhQM3FBAoKAq8MUukIBOOYfDAV9guuCVEYDoGgK6rdPSIq2mvcSxkILG8OH5LQ
通过转到 https://jwt.io/ 我可以看到有效载荷当前是
{
"token_type": "access",
"exp": 1590910684,
"jti": "73c1bfd9cf0f4f279680f4f8eb054497",
"user_id": 11
}
因此,我们可以看到令牌的第二部分是有效载荷 - 包含声明。
我浏览了
由于您已经为所需的视图 (MyTokenObtainPairView) 创建了一个子类,并为其相应的序列化程序 (MyTokenObtainPairSerializer) 创建了一个子类,因此将以下内容添加到序列化程序
class MyTokenObtainPairSerializer(TokenObtainPairSerializer):
...
@classmethod
def get_token(cls, user):
token = super().get_token(user)
# Add custom claims
token['iat'] = datetime.datetime.now()
token['user'] = user.username
token['date'] = str(datetime.date.today())
return token
然后,当您 POST 到达同一位置时,您将获得这样的访问令牌
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNTkwOTE0MTk4LCJqdGkiOiJhZDZmNzZhZjFmOGU0ZWJlOGI2Y2Y5YjQ4MGQzZjY2MiIsInVzZXJfaWQiOjExLCJpYXQiOjE1OTA5MTc0OTgsInVzZXIiOiJ0aWFnbyIsImRhdGUiOiIyMDIwLTA1LTMxIn0.-5U9P-WWmhlOenzCvc6b7_71Tz17LyNxe_DOMwwqH4RqrNsilVukEcZWFRGupLHRZjIvPya2QJGpiju9ujzQuw
使用 JWT,您可以看到相应的负载变化
{
"token_type": "access",
"exp": 1590914198,
"jti": "ad6f76af1f8e4ebe8b6cf9b480d3f662",
"user_id": 11,
"iat": 1590917498,
"user": "tiago",
"date": "2020-05-31"
}
在你的views.py
from rest_framework_simplejwt.tokens import RefreshToken
from rest_framework.response import Response
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import AllowAny
from decouple import config
from django.contrib.auth import authenticate
import jwt
@api_view(['POST'])
@permission_classes([AllowAny])
def get_tokens_for_user(request):
username = request.POST.get("username")
password = request.POST.get("password")
user = authenticate(username=username, password=password);
if user is not None:
refreshToken = RefreshToken.for_user(user)
accessToken = refreshToken.access_token
decodeJTW = jwt.decode(str(accessToken), config('SECRET_KEY'), algorithms=["HS256"]);
# add payload here!!
decodeJTW['iat'] = '1590917498'
decodeJTW['user'] = 'tiago'
decodeJTW['date'] = '2020-05-31'
#encode
encoded = jwt.encode(decodeJTW, config('SECRET_KEY'), algorithm="HS256")
return Response({
'status': True,
'refresh': str(refreshToken),
'access': str(encoded),
})
else:
return Response({
'status': False
})
# No backend authenticated the credentials
在你的urls.py
from django.urls import path, include
from .views import get_tokens_for_user
urlpatterns = [
path('login/', get_tokens_for_user, name="login"),
]
在你的settings.py
from pathlib import Path
from datetime import timedelta
from decouple import config
...
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = config('SECRET_KEY')
# Application definition
INSTALLED_APPS = [
...
# Rest
'rest_framework',
...
]
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework_simplejwt.authentication.JWTAuthentication',
],
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
]
}
# JWT
# https://django-rest-framework-simplejwt.readthedocs.io/en/latest/settings.html
SIMPLE_JWT = {
'ACCESS_TOKEN_LIFETIME': timedelta(minutes=60),
'REFRESH_TOKEN_LIFETIME': timedelta(days=1),
'AUTH_HEADER_TYPES': ('Bearer',),
'SIGNING_KEY': config('SECRET_KEY'),
'VERIFYING_KEY': config('SECRET_KEY'),
'ALGORITHM': 'HS256',
}
在你的根目录下添加 .env
SECRET_KEY = 'ep@4ojr4m!h73y2j(Whosebug)kra1*@tqel626wf@&p60)7u!6552+-'
运行时值
decodeJTW = {
'token_type': 'access',
'exp': 1612651527,
'jti': '7f415b28610348468ce74ec0f480fad1',
'user_id': 2,
'iat': '1590917498',
'user': 'tiago',
'date': '2020-05-31'
}
encode = {
"status":true,
"refresh":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTYxMjczNDU0NywianRpIjoiMDQ0MDI3ZTQzMTc2NDFiNDhhOGI2MjU4MjE4ZGZjNDkiLCJ1c2VyX2lkIjoyfQ.Qf0YfJLAmdYuavDHVng7Bwjmka551G6c1Gi4e-UdRuc",
"access":"b'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjEyNjUxNzQ3LCJqdGkiOiI2OWEzNjYwYjYxMTk0MzVjYjljZTA0OGQ3MmE1ODk1YSIsInVzZXJfaWQiOjIsImlhdCI6IjE1OTA5MTc0OTgiLCJ1c2VyIjoidGlhZ28iLCJkYXRlIjoiMjAyMC0wNS0zMSJ9.XUMvhL13zDZdbjYYPkYnwlZoHN6U7Zc3xUzXsKoVj2I'"
}
当我来到这里寻找一种解决方案,在使用 dj-rest-auth and djangorestframework_simplejwt I found a solution in the code 时将令牌过期添加到响应中(显然没有记录?):
有一个名为 JWT_AUTH_RETURN_EXPIRATION 的设置,如果设置为 True,则会将过期时间添加到响应中,如下所示:
{
"access_token": "ACCESS_TOKEN_STRING",
"refresh_token": "REFRESH_TOKEN_STRING",
"user": {
"pk": PK,
"email": "USER_EMAIL"
},
"access_token_expiration": "2021-02-10T10:40:46.883715Z",
"refresh_token_expiration": "2021-02-11T10:35:46.883728Z"
}
与刷新相同:
{
"access": "ACCESS_TOKEN_STRING",
"access_token_expiration": "2021-02-10T10:47:57.325545Z"
}