简体   繁体   English

Django DRF令牌认证

[英]Django DRF Token Authentication

I'm having issues with DRF's token based authentication. 我在DRF基于令牌的身份验证时遇到问题。 Following is my landing page code (after login): 以下是我的目标网页代码(登录后):

@api_view(['GET','POST'],)
def landing(request):
    this_tenant=request.user.tenant
    end=date_first.date.today()
    start=end-date_first.timedelta(days=30)
    sales_daily=sales_day_wise(start, end, this_tenant)
    invoice_value=sales_raised_value(start, end, this_tenant)
    payment_value=sales_collected_value(start, end, this_tenant)
    return render(request,'landing.html', {'sales_daily':json.dumps(sales_daily, cls=DjangoJSONEncoder),\
        'invoice_value':json.dumps(invoice_value, cls=DjangoJSONEncoder), \
        'payment_value':json.dumps(payment_value, cls=DjangoJSONEncoder)})

I was using Django's built-in login view to authenticate and log in a user, then I revised to consider putting token in the header. 我使用Django的内置登录视图对用户进行身份验证和登录,然后进行了修改以考虑将令牌放入标头中。 But that is also not working 但这也不起作用

This is my login code: 这是我的登录代码:

#Redirect authenticated users to landing page
def custom_login(request):
    if request.user.is_authenticated():
        token, created = Token.objects.get_or_create(user=request.user)
        request.session['AUTHORIZATION'] = "TOKEN "+token.key
        return redirect(landing)
    else:
        return login(request)

Following is my DRF settings: 以下是我的DRF设置:

REST_FRAMEWORK = {
    'DEFAULT_RENDERER_CLASSES': (
        'rest_framework.renderers.JSONRenderer',
    ),
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.TokenAuthentication',
        # 'rest_framework.authentication.SessionAuthentication',
    ),
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    ),
}

Issue is, when I'm logging in and going to the landing page via browser, DRF is not working and I'm getting the following error: 问题是,当我通过浏览器登录并进入登录页面时,DRF无法正常工作,并且出现以下错误:

{"detail":"Authentication credentials were not provided."}

The reason is the custom DRF header (AUTHENTICATION = TOEKN XXXXXXXXXX) is not present in the request. 原因是请求中不存在自定义DRF标头(AUTHENTICATION = TOEKN XXXXXXXXXX)。

However, if I use Postman and put in the custom header (AUTHENTICATION = TOKEN XXXXXXXXXXXX), then it works. 但是,如果我使用Postman并放入自定义标头(AUTHENTICATION = TOKEN XXXXXXXXXXXX),则它可以工作。

How do I solve it? 我该如何解决?

Would this mean I would need a custom header for every view? 这是否意味着每个视图都需要自定义标题?

And on using DRF Token, does it open up CSRF vulnerability (this question: Django DRF - How to do CSRF validation with token authentication )? 在使用DRF令牌时,是否会打开CSRF漏洞(此问题: Django DRF-如何使用令牌身份验证进行CSRF验证 )?

Thanks a lot!! 非常感谢!!

  • How do I solve it? 我该如何解决? Would this mean I would need a custom header for every view? 这是否意味着每个视图都需要自定义标题? TokenAuthentication is used for Single Page App and the token in Request Header needs to be provided by API client(Postman, Javascript or any other client) on each request. TokenAuthentication用于Single Page App,并且请求标头中的令牌需要由API客户端(邮递员,Javascript或任何其他客户端)在每个请求上提供。 In your case, if you want to use Django views you should activate SessionAuthentication. 对于您的情况,如果要使用Django视图,则应激活SessionAuthentication。 TokenAuthentication and SessionAuthentication can co-exist. 令牌认证和会话认证可以共存。 One way is to save the token in the cookie in your in custom login view and read it by javascript client. 一种方法是将令牌保存在自定义登录视图中的cookie中,并由javascript客户端读取。

  • On using DRF Token, does it open up CSRF vulnerability (this question: Django DRF - How to do CSRF validation with token authentication )? 使用DRF令牌时,是否会打开CSRF漏洞(此问题:Django DRF-如何使用令牌身份验证进行CSRF验证)? Yes. 是。 But there are ways to secure the requests. 但是,有一些方法可以保护请求。 According to DRF documentation "If you use token authentication in production you must ensure that your API is only available over https". 根据DRF文档“如果在生产中使用令牌身份验证,则必须确保您的API仅可通过https使用”。 Also, make sure set ALLOWED_HOSTS in settings to the domains that you want Django to respond to so the server does not respond to requests with other origins. 另外,请确保在设置中将ALLOWED_HOSTS设置为您希望Django响应的域,以便服务器不响应其他来源的请求。 There other more secure Auths can be used beside TokenAuthentication like JWT that has been mentioned above. 除了令牌身份验证(如上面提到的JWT)之外,还可以使用其他更安全的Auth。

You need to learn the basics first. 您需要先学习基础知识。 What is HTTP, what is HTTP headers, what is Django session (it's not an HTTP header and contents of the session doesn't affect the headers), read Django REST Framework documentation on token authentication. 什么是HTTP,什么是HTTP标头,什么是Django会话(这不是HTTP标头,并且该会话的内容不会影响标头),请阅读有关令牌认证的Django REST Framework文档。

If you want to test your views in browsers, then explicitly allow Django Session authentication in the DRF DEFAULT_AUTHENTICATION_CLASSES configuration variable. 如果要在浏览器中测试视图,请在DRF DEFAULT_AUTHENTICATION_CLASSES配置变量中显式允许Django会话身份验证。 It can coexist with token authentication. 它可以与令牌认证共存。

You can't make plain web browser append token to the HTTP request unless you're using some plugin like RESTClient, or DHC or REST Easy. 除非您使用诸如RESTClient,DHC或REST Easy之类的插件,否则无法使普通的Web浏览器将令牌附加到HTTP请求。

You're adding token to the Django session but you have disabled session authentication in DRF and even if you'd enable it, DRF doesn't read token from Django session because API client has no way to add Token to the Django session. 您正在将令牌添加到Django会话中,但是您已在DRF中禁用了会话身份验证,即使您启用了该身份验证,DRF也不会从Django会话中读取令牌,因为API客户端无法将令牌添加到Django会话中。 Even if DRF would read Token from Django sessions it would be totally pointless as the client has no control over contents of the session. 即使DRF会从Django会话中读取令牌,这也完全没有意义,因为客户端无法控制会话的内容。 Session variables are set on the server, not on the client. 会话变量是在服务器上设置的,而不是在客户端上设置的。

REST_FRAMEWORK = {
        'DEFAULT_PERMISSION_CLASSES': [
            'rest_framework.permissions.IsAuthenticated',
        ],
        'DEFAULT_AUTHENTICATION_CLASSES': (
            'rest_framework.authentication.BasicAuthentication',  # enables simple command line authentication
            'rest_framework.authentication.SessionAuthentication',
            'rest_framework.authentication.TokenAuthentication',
        )
    }

Adding 'rest_framework.authentication.SessionAuthentication' has solved this issue most of the time. 大多数情况下,添加'rest_framework.authentication.SessionAuthentication'可以解决此问题。

Alternative 另类

You can use: 您可以使用:

'DEFAULT_AUTHENTICATION_CLASSES': (
       'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
   ),

But now, in order to access protected api urls you must include the Authorization: JWT header. 但是现在,为了访问受保护的api网址,您必须包含Authorization:JWT标头。

If it works with curl or postman, this indicates it is not an issue with the backend. 如果它适用于curl或邮递员,则表明后端不是问题。 This is certainly an issue with the client side code. 客户端代码当然是一个问题。 Have you had a look at your request to your REST api? 您是否看过对REST api的请求? I would recommend that and ensure the token is being passed in the headers and is formatted correctly. 我建议并确保令牌在标头中传递并正确设置格式。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM