【问题标题】:First django rest api call returns request.user as AnonymousUser but further calls return proper user第一个 django rest api 调用将 request.user 作为 AnonymousUser 返回,但进一步调用返回正确的用户
【发布时间】:2022-01-05 21:43:49
【问题描述】:

现在我有一个 api 视图,需要知道当前登录的用户。当我尝试使用已登录的用户调用它时;但是,它返回匿名用户。奇怪的是,如果我再次调用 api 视图,它会返回正确的用户。我正在使用带有 simplejwt 的 django rest 框架和 JSON Web Tokens。现在 ReactJS 中的调用看起来像这样:

const fetchAuthorData = () => {
        axiosInstance.get('authors/')
        .then((res) => {
            setAuthor(res.data)
        }).catch((err) => {
            fetchAuthorData()
        })
        
        fetchAuthorThreads()
        fetchAuthorArticles()
    }

但是,我知道一遍又一遍地递归调用它是非常危险的,因为即使我重定向如果用户在此递归 api 调用之前实际上没有登录,如果以某种方式失败,我的服务器将因 api 调用而过载。有谁知道我怎么做才能让我的 api 在第一次调用时正确识别用户是否登录?

这是我的登录视图:

axiosInstance.post('author-auth/token/', {
                email: formData.email,
                password: formData.password,
            }).then((response) => {
                localStorage.setItem('access_token', response.data.access)
                localStorage.setItem('refresh_token', response.data.refresh)
                axiosInstance.defaults.headers['Authorization'] = 
                    'JWT ' + localStorage.getItem('access_token')
                    history.push('/')
            }).catch((err) => {
                alert("Make Sure Login Credentials Are Correct")
            })

这是错误的视图:

@api_view(['GET'])
def author(request):
    print(request.user)
    if request.user.is_authenticated:
        author = request.user
        serializer = AuthorAccessSerializer(author, many=False)
        return Response(serializer.data)
    else:
        return HttpResponse(status=400)

在此,request.user 是匿名用户,即使我已登录

这是另一个奇怪的视图的类似部分

@api_view(['GET', 'POST'])
def articles(request):
    if request.method == 'GET':
        category_name = request.query_params['category']
        dash = request.query_params['dash']
        #this part is very similiar and works for some reason
        if dash == "True":
            if request.user.is_authenticated:
                articles = Article.objects.filter(author=request.user)
            else:
                return HttpResponse(status=401)
        # *end part*
        elif category_name:
            try:
                category = Category.objects.get(name__icontains=category_name)
            except:
                return HttpResponse(status=400, content="Category not found")
            articles = Article.objects.filter(category=category)
        else:
            articles = Article.objects.all()
        serializer = ArticleSerializer(articles, many=True)
        
        return Response(serializer.data)

这是我的 axios 设置:

export const axiosInstance = axios.create({
    baseURL: baseURL,
    timeout: 5000,
    headers : {
        Authorization: localStorage.getItem('access_token')
            ? 'JWT' + localStorage.getItem('access_token')
            : null,
        'Content-Type' : 'application/json',
        accept : 'application/json'
    }
})

这是我的休息框架和 JWT 身份验证设置:

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.AllowAny'
    ],
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    ),
}

SIMPLE_JWT = {
    'ACCESS_TOKEN_LIFETIME': timedelta(hours=5),
    'REFRESH_TOKEN_LIFETIME': timedelta(days=1),
    'ROTATE_REFRESH_TOKENS': False,
    'BLACKLIST_AFTER_ROTATION': True,
    'UPDATE_LAST_LOGIN': False,

    'ALGORITHM': 'HS256',
    'SIGNING_KEY': SECRET_KEY,
    'VERIFYING_KEY': None,
    'AUDIENCE': None,
    'ISSUER': None,
    'JWK_URL': None,
    'LEEWAY': 0,

    'AUTH_HEADER_TYPES': ('Bearer', 'JWT'),
    'AUTH_HEADER_NAME': 'HTTP_AUTHORIZATION',
    'USER_ID_FIELD': 'id',
    'USER_ID_CLAIM': 'user_id',
    'USER_AUTHENTICATION_RULE': 'rest_framework_simplejwt.authentication.default_user_authentication_rule',

    'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',),
    'TOKEN_TYPE_CLAIM': 'token_type',

    'JTI_CLAIM': 'jti',

    'SLIDING_TOKEN_REFRESH_EXP_CLAIM': 'refresh_exp',
    'SLIDING_TOKEN_LIFETIME': timedelta(minutes=5),
    'SLIDING_TOKEN_REFRESH_LIFETIME': timedelta(days=1),
}

ALLOWED_HOSTS=['127.0.0.1', 'http://localhost:5000']
CORS_ORIGIN_ALLOW_ALL = False
CORS_ORIGIN_WHITELIST = (
    'http://localhost:3000',
) 

同样,如果我继续调用相同的 api 调用,由于某种原因,它不会更改任何授权标头、令牌或其他任何内容,并且 request.user 可以在我上面的第二个视图中正常工作。谁能告诉我为什么会这样?

【问题讨论】:

  • fetchAuthorThreads() 或 fetchAuthorArticles() 是否控制 localStroage?
  • 不,唯一控制 localStorage 的是作者登录注销,它不会被调用
  • 您能添加您的登录视图吗?为了澄清您的问题,def author 正在打印匿名,但 def articles 正在打印正确的用户或没有响应错误?
  • 如果articles只是没有响应错误,检查request.user是否可用。
  • 是的,你是对的。刚刚添加了登录视图

标签: python django django-rest-framework jwt django-rest-framework-simplejwt


【解决方案1】:

我认为,

                1. localStorage.setItem('access_token', response.data.access)
                2. localStorage.setItem('refresh_token', response.data.refresh)
                3. axiosInstance.defaults.headers['Authorization'] = 
                    'JWT ' + localStorage.getItem('access_token')
                    history.push('/')

登录代码可能会导致问题。

这些代码从不按顺序运行;每个 javascript 都是异步运行的。

这意味着,您的axiosInstance.defaults.headers 可能为空,因为一次执行了 1、2 和 3 行。也就是说axiosInstance.defaults.headers变为null(因为localStorage上没有access_token),那么Js从response.data.access设置access_token。

你最好在第 1 行和第 2 行之后使用带有 .then() 的 promise, 或者在发出 http 请求时获取 axiosInstance 的授权。

【讨论】:

  • 您推荐的第二个选项效果很好!谢谢!
猜你喜欢
  • 2017-01-02
  • 2017-11-22
  • 1970-01-01
  • 2021-08-22
  • 2017-12-02
  • 1970-01-01
  • 2015-05-31
  • 2020-08-26
  • 1970-01-01
相关资源
最近更新 更多