[英]Django REST: How do i return SimpleJWT access and refresh tokens as HttpOnly cookies with custom claims?
I want to send the SimpleJWT
access
and refresh
tokens through HttpOnly
cookie.我想通过
HttpOnly
cookie 发送SimpleJWT
access
和refresh
令牌。 I have customized the claim.我已经定制了索赔。 I have defined a
post()
method in the MyObtainTokenPairView(TokenObtainPairView)
in which I am setting the cookie.我在其中设置 cookie 的
MyObtainTokenPairView(TokenObtainPairView)
中定义了一个post()
方法。 This is my code:这是我的代码:
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
It's returning this error:它返回此错误:
AttributeError: 'RefreshToken' object has no attribute 'access'
The serializer:序列化器:
class MyTokenObtainPairSerializer(TokenObtainPairSerializer):
@classmethod
def get_token(cls, user):
print(type(user))
token = super().get_token(user)
token['email'] = user.email
return token
But it's just not working.但它只是不工作。 I think I should not define a
post()
method here like this.我想我不应该像这样在这里定义
post()
方法。 I think if I can only return the value of the get_token()
function in the serializer, I could set it as HttpOnly
cookie.我想如果我只能在序列化程序中返回
get_token()
function 的值,我可以将其设置为HttpOnly
cookie。 But, I don't know how to do that.但是,我不知道该怎么做。
How do I set the access
and refresh
tokens in the HttpOnly
cookie?如何在
HttpOnly
cookie 中设置access
和refresh
令牌?
EDIT: I made these changes following anowlinorbit 's answer:编辑:我按照anowlinorbit的回答进行了这些更改:
I changed my serializer to this:我将我的序列化程序更改为:
class MyTokenObtainPairSerializer(TokenObtainPairSerializer):
def validate(self, attrs):
attrs = super().validate(attrs)
token = self.get_token(self.user)
token["email"] = self.user.email
return token
Since this token contains the refresh token by default therefore, I decided that returning only this token
would provide both access
and refresh
token.由于此令牌默认包含刷新令牌,因此我决定仅返回此
token
将提供access
令牌和refresh
令牌。 If I add anything like token["access"] = str(token.access_token)
it would just add the access token string inside the refresh token string, which it already contains.如果我添加类似
token["access"] = str(token.access_token)
的东西,它只会在它已经包含的刷新令牌字符串中添加访问令牌字符串。
But again in the view, I could not find how to get the refresh token.但是再次在视图中,我找不到如何获取刷新令牌。 I could not get it using
serializer.validated_data.get('refresh', None)
since now I am returning the token
from serializer which contains everything.我无法使用
serializer.validated_data.get('refresh', None)
获取它,因为现在我从包含所有内容的序列化程序返回token
。
I changed my view to this:我改变了看法:
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
Now it's saying:现在它说:
NameError: name 'token' is not defined
What's wrong here?这里有什么问题? In the view I want to get the
token
returned from serializer, then get the acces token using token.access_token
and set both refresh
and access
as cookies.在视图中,我想获取从序列化程序返回的
token
,然后使用token.access_token
获取访问令牌,并将refresh
和access
设置为 cookies。
I would leave .get_token()
alone and instead focus on .validate()
.我会单独留下
.get_token()
,而是专注于 .validate .validate()
。 In your MyTokenObtainPairSerializer
I would remove your changes to .get_token()
and add the following在您的
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
It is by using the .validate()
method with which you can choose which data you wish to return from the serializer object's validated_data
attribute.通过使用
.validate()
方法,您可以选择希望从序列化器对象的validated_data
属性返回的数据。 NB I have also included the refresh token in the data which the serializer returns.注意我还在序列化程序返回的数据中包含了刷新令牌。 Having both a refresh and access token is important.
同时拥有刷新和访问令牌很重要。 If a user doesn't have the refresh token they will have to login again when the access token expires.
如果用户没有刷新令牌,他们将不得不在访问令牌过期时再次登录。 The refresh token allows them to get a new access token without having to login again.
刷新令牌使他们无需再次登录即可获得新的访问令牌。
If for whatever reason you don't want the refresh token, remove it from your validate()
serializer method and adjust the view accordingly.如果出于某种原因您不想要刷新令牌,请将其从您的
validate()
序列化程序方法中删除并相应地调整视图。
In this post method, we validate the serializer and access its validated data.在这个 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)
If you didn't want the refresh token, you would remove the line beginning refresh =
and remove the line where you add the refresh
cookie.如果您不想要刷新令牌,您将删除以
refresh =
开头的行并删除添加refresh
cookie 的行。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.