Django 授权请求,即使设置了 permissions.AllowAny

Posted

技术标签:

【中文标题】Django 授权请求,即使设置了 permissions.AllowAny【英文标题】:Django authorizing request even if permissions.AllowAny is set 【发布时间】:2021-08-28 18:38:00 【问题描述】:

我正在开发一个 Django REST 框架项目。我正在使用 JWT 身份验证,在我的登录视图中,我已将权限类设置为 AllowAny。 '

@decorators.api_view(["POST"])
@decorators.permission_classes([permissions.AllowAny])
def login(request):
    print("REQUEST in login = ", request)
    try:
        username = request.data['username']
        print(username)
        user = User.objects.get(username=username)
    except Exception as e:
        return response.Response('username': "User doesn't exist" , status.HTTP_400_BAD_REQUEST)

    try: 
        password = request.data["password"]
        print(password)
    except: 
        return response.Response("password": "Password not valid", status.HTTP_400_BAD_REQUEST)

    user = authenticate(username=username, password=password)
    if user is not None:

        refresh = RefreshToken.for_user(user)
        res = 
            "message": "Logged in successfully",
            "refresh": str(refresh),
            "access": str(refresh.access_token),
                
        return response.Response(res, status.HTTP_200_OK)
    else:
        return response.Response("password": "Password not valid", status=status.HTTP_400_BAD_REQUEST)

当我发送正常请求时,一切都按预期工作。

但是当我将 Authorization 标头设置为空字符串时(或 null 两者都有相同的问题)

授权:null 或 ''

Authorization之所以设置为null,是因为React中的axios。它在本地存储中查找访问令牌。如果不存在,则将其设置为 null。

const axiosInstance = axios.create(
  baseURL: baseURL,
  timeout: 60000,
  headers: 
    Authorization: localStorage.getItem('access_token')
      ? 'Bearer ' + localStorage.getItem('access_token')
      : null,
    'Content-Type': 'application/json',
    accept: 'application/json',
  ,
);

我已经在 django 中将默认身份验证设置为 JWT。

REST_FRAMEWORK = 
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    )

我可以考虑在登录时删除 Authorization 标头并设置新的 axiosInstance。但这会使代码不那么清晰。请提出任何解决此问题的方法。

【问题讨论】:

【参考方案1】:

您可以提供rest_framework_simplejwt.authentication.JWTAuthentication 的自定义子类,并以您喜欢的方式处理标头的值。

import re
from rest_framework_simplejwt.authentication import JWTAuthentication

class CustomJWTAuthentication(JWTAuthentication):
    def get_header(self, request):
        header = super().get_header(request)
        # value is usually "Bearer <token>"
        if header is None:
            return header

        if not re.match("Bearer \S+", header)
            return None
        
        return header

我们这样做是因为JWTAuthentication 只会在JWTAuthentication.get_header() 返回None 时跳过检查,否则它将继续进行。

因此,在 axios 中提供诸如 nullundefined 或空字符串之类的值将发送它的字符串表示形式(例如,null 将是“null”)并且JWTAuthentication 将按原样处理。


在 django 之外但在 axios 中的另一个解决方案是不通过 tranformRequest 包含它。

const apiAxios = axios.create(
  baseURL: baseURL.href,
  transformRequest: [
    function (data, headers) 
      const accessToken = window.localStorage.getItem("accessToken")
      if (accessToken) 
        headers['Authorization'] = `Bearer $accessToken`
       else 
        delete headers.Authorization
      

      return JSON.stringify(data)
    
  ],
  headers: defaultApiHeaders,
);

【讨论】:

以上是关于Django 授权请求,即使设置了 permissions.AllowAny的主要内容,如果未能解决你的问题,请参考以下文章

Facebook 授权 w/permissions 请求产生“页面未找到”

需要 Django 权限

Django Tastypie 总是返回 401 未经授权

Flutter Permissions 状态 NotAgain 即使在第一次启动时

Django:request.user.user_permissions 总是无

Django授权 - 在函数调用中返回重定向