简体   繁体   English

Django REST:如何使用自定义声明将 SimpleJWT 访问和刷新令牌作为 HttpOnly cookies 返回?

[英]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 accessrefresh令牌。 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 中设置accessrefresh令牌?

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获取访问令牌,并将refreshaccess设置为 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.

相关问题 使用 Django Rest 框架时,如何在 SimpleJWT 自定义令牌中返回 401 响应? - How do I return a 401 response in a SimpleJWT Custom Token when using the Django Rest Framework? Django:当令牌存储在 HttpOnly cookies 中时,如何更新 SimpleJWT 访问令牌? - Django: How to renew SimpleJWT access token when token are stored in HttpOnly cookies? Django:身份验证凭据未提供错误,因为访问和刷新令牌设置为 HttpOnly cookies 没有授权 header - Django: Authentication credentials not povided error as access and refresh tokens are set as HttpOnly cookies without Authorization header 如何使用 DRF djangorestframework-simplejwt package 在 HttpOnly cookies 中存储 JWT 令牌? - How to store JWT tokens in HttpOnly cookies with DRF djangorestframework-simplejwt package? 如何在 Django 中设置 HttpOnly cookie? - How do I set HttpOnly cookie in Django? 在django-rest-framework-simplejwt注册后返回令牌 - return token after registration with django-rest-framework-simplejwt 如何在“django-rest-framework-simplejwt”中使用“email”而不是“username”来生成令牌? - How can I use `email` in "django-rest-framework-simplejwt" instead of `username` to generate token? 如何在 user.save() 之后验证并返回访问和刷新令牌 - How to validate and return access and refresh tokens after user.save() 如何在 Django 中安全地存储 OAuth2 访问和刷新令牌 - How to securely store OAuth2 access and refresh tokens in Django 如何将令牌有效负载的“user_id”放入 JSON POST 表单中?Django REST、simpleJWT、Vue3 - How do you get the "user_id" of the token payload into the JSON POST form?Django REST, simpleJWT, Vue3
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM