Django REST Framework与CSRF / CORS的TokenAuthentication问题

时间:2016-01-14 12:10:09

标签: django django-rest-framework django-csrf django-cors-headers

我在Django REST Framework中使用TokenAuthentication让脚本远程访问我的API。运行API的域位于TLS证书后面。

我已经浏览了很多来源,并在来到这里找出我的问题之前尝试了很多选择。简而言之,当我尝试发布时,我会继续收到public class IncrementIntProcessor implements Processor { private String headerName; private int delta = 1; public IncrementIntProcessor(String headerName){ this.headerName = headerName; } public IncrementIntProcessor(String headerName, int delta){ this.headerName = headerName; this.delta = delta; } @Override public void process(Exchange exchange) throws Exception { int num = (exchange.getIn().getHeader(headerName)==null ? 0 : exchange.getIn().getHeader(headerName, Integer.class)); exchange.getIn().setHeader(headerName, (num+delta)); } } 错误。

以下是我的观点:

            ....
            .process(new IncrementIntProcessor("intHeader", 50))
            .log(LoggingLevel.INFO, "${header.intHeader}")
            ....

CSRF verification failed. Request aborted.装饰者在这里什么也没做。所以,我也在# @csrf_exempt @api_view(['POST']) @authentication_classes((TokenAuthentication,)) @permission_classes((permissions.IsAuthenticated,)) def create_object(request): 上尝试了它:

csrf_exempt

我甚至尝试过编写自定义装饰器,并使用this suggestion。即使我这样做,我甚至无法在失败之前让装饰器执行。也许我的中间件订购存在问题?

urls.py

以下是我的django cors设置:

url(r'^create_object/', csrf_exempt(views.create_object),),

2 个答案:

答案 0 :(得分:2)

正如所承诺的,这是我提出的解决方案。不可否认,这并不完美。我无法找出潜在的问题(为什么在HTTPS上应用程序没有响应csrf_exemptCORS_REPLACE_HTTPS_REFERER),但提出了这个有限的解决方案。

第1步

首先,我将整个CsrfViewMiddleware类子类化为我自己的版本,并将其放入我的中间件(标记为原始序列的更改):

'sslify.middleware.SSLifyMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',

'corsheaders.middleware.CorsMiddleware',

'django.middleware.common.CommonMiddleware',
#'django.middleware.csrf.CsrfViewMiddleware',    ##CHANGE
'myapp.csrf.CsrfViewMiddleware',    ##CHANGE

'corsheaders.middleware.CorsPostCsrfMiddleware',

'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.RemoteUserMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',

CsrfViewMiddleware我的版本第160行,我将现有条件替换为:

            acceptable_referers = ['https://%s' % u for u in settings.CORS_ORIGIN_WHITELIST] + ['http://%s' % u for u in settings.CORS_ORIGIN_WHITELIST]
            if not same_origin(referer, good_referer) and referer not in acceptable_referers:

这让我超越了无效的引用者问题,这很好,因为我将域名列入白名单。它基本上与CORS_REPLACE_HTTPS_REFERER的结果相同。我的版本使用settings.CORS_ORIGIN_WHITELIST交叉引用了引用标头,而CORS_REPLACE_HTTPS_REFERER方法暂时更改了request引用者。在我看来,似乎没有足够的安全解决方案 - 但这是另一个对话。

第2步

此时,我仍然收到csrf cookie not found错误。为了避免这个问题,并且由于csrf_exempt没有重新编码(好像中间件执行得太早),我添加了一个新的中间件:

'sslify.middleware.SSLifyMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',

'myapp.csrf.CsrfSkipMiddleware'    ##ADDED

'corsheaders.middleware.CorsMiddleware',

'django.middleware.common.CommonMiddleware',
#'django.middleware.csrf.CsrfViewMiddleware',    ##REMOVED
'myapp.csrf.CsrfViewMiddleware',    ##ADDED

'corsheaders.middleware.CorsPostCsrfMiddleware',

'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.RemoteUserMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',

这个新的中间件实际上在请求对象(_dont_enforce_csrf_checks)上设置了一个标志,该标志已存在于CsrfViewMiddleware的库存版本上,并告诉脚本忽略其余的csrf检查。为此,它会根据我选择从settings.CSRF_SKIP_URLS中的csrf中删除的路径列表检查页面路径。

class CsrfSkipMiddleware(object):

    def process_request(self, request):
        CSRF_SKIP_URLS = [re.compile(expr) for expr in settings.CSRF_SKIP_URLS]
        path = request.path_info.lstrip('/')

        if any(m.match(path) for m in CSRF_SKIP_URLS):
            setattr(request, '_dont_enforce_csrf_checks', True)

<强> THOUGHTS

同样,不是最佳实施。但是,为了我的目的,它是有效的。仍然欢迎思考。

答案 1 :(得分:0)

我看到你正在使用django cors标头。 我遇到了类似的问题,并指出: CORS_REPLACE_HTTPS_REFERER = True settings.py解决了问题。