Django:使用中间件将 JWT 更新并设置为 HttpOnly cookie。 Response() 返回 django.template.response.ContentNotRenderedE

Posted

技术标签:

【中文标题】Django:使用中间件将 JWT 更新并设置为 HttpOnly cookie。 Response() 返回 django.template.response.ContentNotRenderedError【英文标题】:Django: Renew and set JWTs as HttpOnly cookie using a middleware. Response() returning django.template.response.ContentNotRenderedError 【发布时间】:2021-05-20 17:14:56 【问题描述】:

我有一个自定义中间件,我在其中添加 SimpleJWR HTTP_AUTHORIZATION 到每个授权请求,因为我正在使用 HttpOnly cookie。另外在这里我添加了代码来检查access 令牌是否有效。如果不是,则使用requests 发送请求,该请求获取新的access 令牌并将其设置为HttpOnly cookie。到目前为止,我能够在新的access 令牌过期后获得它。但是,我发送请求的 url 返回了这个错误:

raise ContentNotRenderedError(
django.template.response.ContentNotRenderedError: The response content must be rendered before it can be accessed.

在第一次请求时它就起作用了。它返回响应并将令牌保存为HttpOnly cookie,但在令牌过期后,如果我再次发出请求,而不是(我想要发生的)将令牌保存为HttpOnly cookie 并再次返回相同的响应,它正在返回错误。

我认为问题出在response 语句中。我的中间件:

import jwt
import datetime
import requests
import json

from rest_framework.response import Response
from django.conf import settings

class AuthorizationHeaderMiddleware:
    def __init__(self, get_response=None):
        self.get_response = get_response

    def __call__(self, request):
        access_token = request.COOKIES.get('access')
        refesh_token = request.COOKIES.get('refresh')
        print(refesh_token)
        # check if the access token is valid
        # if not, send new access token to cookie
        if access_token:
            key = settings.SECRET_KEY
        try:
            decoded_access_token = jwt.decode(access_token, key, algorithms=["HS256"])
        except jwt.ExpiredSignatureError:
            # Signature has expired
            print("expired; sending for new token")
            url = 'http://127.0.0.1:8000/api/token/refresh/'
            data = "refresh": refesh_token
            resp = requests.post(
                url, 
                data=json.dumps(data),
                headers = 'content-type': 'application/json'
                )
            result = resp.json()
            new_access_token = result['access']
            response = Response()
            response.set_cookie('access', new_access_token, httponly=True)
            response.set_cookie('set', 'new')
            return response

            request.META['HTTP_AUTHORIZATION'] = f'Bearer access_token'
        return self.get_response(request)

这个错误是怎么来的,我该如何解决?

【问题讨论】:

【参考方案1】:

试试这个:

def __call__(self, request):
    access_token = request.COOKIES.get('access')
    refesh_token = request.COOKIES.get('refresh')
    print(refesh_token)
    # check if the access token is valid
    # if not, send new access token to cookie
    if access_token is not None:
        key = settings.SECRET_KEY
    else:
        return Response("Error" : "No token found")
    try:
        decoded_access_token = jwt.decode(access_token, key, algorithms=["HS256"])
        request.META['HTTP_AUTHORIZATION'] = f'Bearer access_token'
        return self.get_response(request)
    except jwt.ExpiredSignatureError:
        # Signature has expired
        print("expired; sending for new token")
        url = 'http://127.0.0.1:8000/api/token/refresh/'
        data = "refresh": refesh_token
        resp = requests.post(
            url, 
            data=json.dumps(data),
            headers = 'content-type': 'application/json'
            )
        result = resp.json()
        new_access_token = result['access']
        response = Response()
        response.set_cookie('access', new_access_token, httponly=True)
        response.set_cookie('set', 'new')
        request.META['HTTP_AUTHORIZATION'] = f'Bearer new_access_token'
        
        return self.get_response(request)

【讨论】:

添加这些后我得到了这些错误:if response.get('X-Frame-Options') is not None: AttributeError: 'NoneType' object has no attribute 'get' 因为如果access_token当时没有在cookie中找到access_token返回None。我们的条件不满足。所以__call__ 方法没有返回任何响应。我编辑了我的答案。 另一种设置和获取 httponly cookie 的方法。检查这个:***.com/a/66248320/14131913) 并看到这个***.com/a/63622625/14131913 或github.com/HarryAustin/tweeter-DrfTest-httonlycookie/blob/main/…

以上是关于Django:使用中间件将 JWT 更新并设置为 HttpOnly cookie。 Response() 返回 django.template.response.ContentNotRenderedE的主要内容,如果未能解决你的问题,请参考以下文章

用于通道 websocket 身份验证的 Django jwt 中间件

Django DRF websocket 通道 2 并使用来自 Simple JWT 的令牌进行授权

Jwt Bearer Authentication 中间件始终将 User.Identity.IsAuthenticated 设置为 false

如何添加身份验证中间件 JWT django?

缺少 Django、React 和 Rest Framework JWT 身份验证标头

如何添加Authenticate Middleware JWT django?