我遇到了DRF基于令牌的身份验证问题。以下是我的登录页面代码(登录后):
@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)})
我使用Django的内置登录视图来验证和登录用户,然后我修改了考虑将标记放入标题。但那也行不通了
这是我的登录代码:
#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)
以下是我的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',
),
}
问题是,当我登录并通过浏览器访问目标网页时,DRF无效,我收到以下错误:
{"detail":"Authentication credentials were not provided."}
原因是请求中不存在自定义DRF标头(AUTHENTICATION = TOEKN XXXXXXXXXX)。
但是,如果我使用Postman并放入自定义标题(AUTHENTICATION = TOKEN XXXXXXXXXXXX),那么它可以正常工作。
我该如何解决?
这是否意味着每个视图都需要一个自定义标题?
使用DRF令牌时,是否会打开CSRF漏洞(此问题:Django DRF - How to do CSRF validation with token authentication)?
非常感谢!!
答案 0 :(得分:0)
您需要先学习基础知识。什么是HTTP,什么是HTTP头,什么是Django会话(它不是HTTP头,会话的内容不影响头),阅读令牌认证的Django REST Framework文档。
如果要在浏览器中测试视图,请在DRF DEFAULT_AUTHENTICATION_CLASSES
配置变量中明确允许Django Session身份验证。它可以与令牌认证共存。
除非您使用RESTClient或DHC或REST Easy之类的插件,否则无法为HTTP请求添加普通Web浏览器附加标记。
您正在向Django会话添加令牌,但您已在DRF中禁用了会话身份验证,即使您启用它,DRF也不会从Django会话中读取令牌,因为API客户端无法将令牌添加到Django会话。即使DRF从Django会话中读取令牌,它也完全没有意义,因为客户端无法控制会话内容。会话变量在服务器上设置,而不是在客户端上设置。
答案 1 :(得分:0)
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',
)
}
添加'rest_framework.authentication.SessionAuthentication'
大部分时间可以解决此问题。
替代
您可以使用:
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
),
但是现在,要访问受保护的api网址,您必须包含Authorization:JWT标头。
答案 2 :(得分:0)
我该如何解决?这是否意味着每个视图都需要自定义标题? TokenAuthentication用于Single Page App,并且请求标头中的令牌需要由API客户端(邮递员,Javascript或任何其他客户端)在每个请求上提供。对于您的情况,如果要使用Django视图,则应激活SessionAuthentication。令牌认证和会话认证可以共存。 一种方法是将令牌保存在自定义登录视图中的cookie中,并由javascript客户端读取。
在使用DRF令牌时,是否会打开CSRF漏洞(此问题:Django DRF-如何使用令牌身份验证进行CSRF验证)? 是。但是,有一些方法可以保护请求。 根据DRF文档 “如果在生产中使用令牌身份验证,则必须确保您的API仅可通过https使用”。 另外,请确保在设置中将ALLOWED_HOSTS设置为您希望Django响应的域,以便服务器不响应其他来源的请求。除了TokenAuthentication之外,还可以使用其他更安全的Auth,例如上面提到的JWT。
答案 3 :(得分:0)
如果它适用于curl或邮递员,则表明它与后端无关。客户端代码当然是一个问题。您是否看过对REST api的请求?我建议您并确保令牌在标头中传递并正确设置格式。