Django REST:我如何 return SimpleJWT 访问和刷新令牌作为具有自定义声明的 HttpOnly cookie?
Django REST: How do i return SimpleJWT access and refresh tokens as HttpOnly cookies with custom claims?
我想通过 HttpOnly
cookie 发送 SimpleJWT
access
和 refresh
令牌。我已经定制了索赔。我在设置 cookie 的 MyObtainTokenPairView(TokenObtainPairView)
中定义了一个 post()
方法。这是我的代码:
from .models import CustomUser
class MyObtainTokenPairView(TokenObtainPairView):
permission_classes = (permissions.AllowAny,)
serializer_class = MyTokenObtainPairSerializer
def post(self, request, *args, **kwargs):
serializer = self.serializer_class()
response = Response()
tokens = serializer.get_token(CustomUser)
access = tokens.access
response.set_cookie('token', access, httponly=True)
return response
return出现了这个错误:
AttributeError: 'RefreshToken' object has no attribute 'access'
序列化程序:
class MyTokenObtainPairSerializer(TokenObtainPairSerializer):
@classmethod
def get_token(cls, user):
print(type(user))
token = super().get_token(user)
token['email'] = user.email
return token
但这就是行不通。我想我不应该像这样在这里定义一个 post()
方法。我想如果我只能 return 序列化程序中 get_token()
函数的值,我可以将它设置为 HttpOnly
cookie。但是,我不知道该怎么做。
如何在 HttpOnly
cookie 中设置 access
和 refresh
标记?
编辑:
我根据 anowlinorbit 的回答进行了这些更改:
我将我的序列化程序更改为:
class MyTokenObtainPairSerializer(TokenObtainPairSerializer):
def validate(self, attrs):
attrs = super().validate(attrs)
token = self.get_token(self.user)
token["email"] = self.user.email
return token
由于此令牌默认包含刷新令牌,因此我决定 return 仅此 token
将同时提供 access
和 refresh
令牌。
如果我添加类似 token["access"] = str(token.access_token)
的任何内容,它只会在它已经包含的刷新令牌字符串中添加访问令牌字符串。
但再次在视图中,我找不到如何获取刷新令牌。我无法使用 serializer.validated_data.get('refresh', None)
获取它,因为现在我正在从包含所有内容的序列化器中 returning token
。
我改变了对这个的看法:
class MyObtainTokenPairView(TokenObtainPairView):
permission_classes = (permissions.AllowAny,)
serializer_class = MyTokenObtainPairSerializer
def post(self, request, *args, **kwargs):
response = super().post(request, *args, **kwargs)
response.set_cookie('token', token, httponly=True)
return response
现在是:
NameError: name 'token' is not defined
这是怎么回事?在视图中,我想从序列化程序中获取 token
returned,然后使用 token.access_token
获取访问令牌并将 refresh
和 access
设置为 cookie。
我会不理会 .get_token()
,而是专注于 .validate()
。在您的 MyTokenObtainPairSerializer
中,我会删除您对 .get_token()
的更改并添加以下内容
def validate(self, attrs):
data = super().validate(attrs)
refresh = self.get_token(self.user)
data["refresh"] = str(refresh) # comment out if you don't want this
data["access"] = str(refresh.access_token)
data["email"] = self.user.email
""" Add extra responses here should you wish
data["userid"] = self.user.id
data["my_favourite_bird"] = "Jack Snipe"
"""
return data
通过使用 .validate()
方法,您可以从序列化程序对象的 validated_data
属性中选择要 return 的数据。 N.B. 我还在序列化程序 return 的数据中包含了刷新令牌。同时拥有刷新令牌和访问令牌很重要。如果用户没有刷新令牌,他们将必须在访问令牌过期时重新登录。刷新令牌允许他们获得新的访问令牌而无需再次登录。
如果出于某种原因您不想要刷新令牌,请将其从您的 validate()
序列化程序方法中删除并相应地调整视图。
在此 post 方法中,我们验证序列化程序并访问其验证数据。
def post(self, request, *args, **kwargs):
# you need to instantiate the serializer with the request data
serializer = self.serializer(data=request.data)
# you must call .is_valid() before accessing validated_data
serializer.is_valid(raise_exception=True)
# get access and refresh tokens to do what you like with
access = serializer.validated_data.get("access", None)
refresh = serializer.validated_data.get("refresh", None)
email = serializer.validated_data.get("email", None)
# build your response and set cookie
if access is not None:
response = Response({"access": access, "refresh": refresh, "email": email}, status=200)
response.set_cookie('token', access, httponly=True)
response.set_cookie('refresh', refresh, httponly=True)
response.set_cookie('email', email, httponly=True)
return response
return Response({"Error": "Something went wrong", status=400)
如果您不需要刷新令牌,您可以删除以 refresh =
开头的行并删除添加 refresh
cookie 的行。
我想通过 HttpOnly
cookie 发送 SimpleJWT
access
和 refresh
令牌。我已经定制了索赔。我在设置 cookie 的 MyObtainTokenPairView(TokenObtainPairView)
中定义了一个 post()
方法。这是我的代码:
from .models import CustomUser
class MyObtainTokenPairView(TokenObtainPairView):
permission_classes = (permissions.AllowAny,)
serializer_class = MyTokenObtainPairSerializer
def post(self, request, *args, **kwargs):
serializer = self.serializer_class()
response = Response()
tokens = serializer.get_token(CustomUser)
access = tokens.access
response.set_cookie('token', access, httponly=True)
return response
return出现了这个错误:
AttributeError: 'RefreshToken' object has no attribute 'access'
序列化程序:
class MyTokenObtainPairSerializer(TokenObtainPairSerializer):
@classmethod
def get_token(cls, user):
print(type(user))
token = super().get_token(user)
token['email'] = user.email
return token
但这就是行不通。我想我不应该像这样在这里定义一个 post()
方法。我想如果我只能 return 序列化程序中 get_token()
函数的值,我可以将它设置为 HttpOnly
cookie。但是,我不知道该怎么做。
如何在 HttpOnly
cookie 中设置 access
和 refresh
标记?
编辑: 我根据 anowlinorbit 的回答进行了这些更改:
我将我的序列化程序更改为:
class MyTokenObtainPairSerializer(TokenObtainPairSerializer):
def validate(self, attrs):
attrs = super().validate(attrs)
token = self.get_token(self.user)
token["email"] = self.user.email
return token
由于此令牌默认包含刷新令牌,因此我决定 return 仅此 token
将同时提供 access
和 refresh
令牌。
如果我添加类似 token["access"] = str(token.access_token)
的任何内容,它只会在它已经包含的刷新令牌字符串中添加访问令牌字符串。
但再次在视图中,我找不到如何获取刷新令牌。我无法使用 serializer.validated_data.get('refresh', None)
获取它,因为现在我正在从包含所有内容的序列化器中 returning token
。
我改变了对这个的看法:
class MyObtainTokenPairView(TokenObtainPairView):
permission_classes = (permissions.AllowAny,)
serializer_class = MyTokenObtainPairSerializer
def post(self, request, *args, **kwargs):
response = super().post(request, *args, **kwargs)
response.set_cookie('token', token, httponly=True)
return response
现在是:
NameError: name 'token' is not defined
这是怎么回事?在视图中,我想从序列化程序中获取 token
returned,然后使用 token.access_token
获取访问令牌并将 refresh
和 access
设置为 cookie。
我会不理会 .get_token()
,而是专注于 .validate()
。在您的 MyTokenObtainPairSerializer
中,我会删除您对 .get_token()
的更改并添加以下内容
def validate(self, attrs):
data = super().validate(attrs)
refresh = self.get_token(self.user)
data["refresh"] = str(refresh) # comment out if you don't want this
data["access"] = str(refresh.access_token)
data["email"] = self.user.email
""" Add extra responses here should you wish
data["userid"] = self.user.id
data["my_favourite_bird"] = "Jack Snipe"
"""
return data
通过使用 .validate()
方法,您可以从序列化程序对象的 validated_data
属性中选择要 return 的数据。 N.B. 我还在序列化程序 return 的数据中包含了刷新令牌。同时拥有刷新令牌和访问令牌很重要。如果用户没有刷新令牌,他们将必须在访问令牌过期时重新登录。刷新令牌允许他们获得新的访问令牌而无需再次登录。
如果出于某种原因您不想要刷新令牌,请将其从您的 validate()
序列化程序方法中删除并相应地调整视图。
在此 post 方法中,我们验证序列化程序并访问其验证数据。
def post(self, request, *args, **kwargs):
# you need to instantiate the serializer with the request data
serializer = self.serializer(data=request.data)
# you must call .is_valid() before accessing validated_data
serializer.is_valid(raise_exception=True)
# get access and refresh tokens to do what you like with
access = serializer.validated_data.get("access", None)
refresh = serializer.validated_data.get("refresh", None)
email = serializer.validated_data.get("email", None)
# build your response and set cookie
if access is not None:
response = Response({"access": access, "refresh": refresh, "email": email}, status=200)
response.set_cookie('token', access, httponly=True)
response.set_cookie('refresh', refresh, httponly=True)
response.set_cookie('email', email, httponly=True)
return response
return Response({"Error": "Something went wrong", status=400)
如果您不需要刷新令牌,您可以删除以 refresh =
开头的行并删除添加 refresh
cookie 的行。