Django:在没有 CSRF 令牌的情况下重置密码

Django: resetting password without a CSRF token

我有一个管理 Users. Using the built-in functionality, users can request a password reset from the website and that works great. I have implemented it according to this tutorial so I am using the built-in password reset functionality.

的 Django 网站

我有一个 Android 应用程序,用户应该也可以从中请求重设密码。问题是我没有 CSRF token in the application, and the the built-in password_reset method has the @csrf_protect decorator. This means that I cannot access it without a CSRF token and I also can't modify it with the @csrf_exempt 装饰器。

所以下一个想法是创建一个函数,它生成一个 CSRF 令牌,将其存储在请求中并重定向到发送重置电子邮件的正确 URL。问题是 according to this, django does not allow to pass POST parameters further in a redirect.

因此我的问题是如何在没有 CSRF 令牌的情况下在 Django 中请求重设密码?或者,从应用程序请求此请求的正确方法是什么

我自己找到了解决办法。请随时 post 任何替代解决方案。一个不需要两个单独请求的会特别好。

如果您查看 the password_reset method,您会发现如果请求方法是 POST,它只会尝试将请求作为重置请求进行处理。否则它只是 returns 一个 TemplateResponse 包含一个表单。这也包含 CSRF 令牌作为 cookie。

首先,我向 http://myaddress.com/user/password/reset/ 发送 GET 请求并从响应中提取 CSRF cookie。然后我发送一个 POST 请求,其中包含 cookie、电子邮件地址和 2 headers(见下文)。

这是我从 Android(修剪):

实现的代码
String url = "http://myaddress.com/user/password/reset/";

GET 请求:

HttpClient httpClient = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(url);
CookieStore cookieStore = new BasicCookieStore();
HttpContext localContext = new BasicHttpContext();
localContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
HttpResponse httpResponse = httpClient.execute(httpGet, localContext);

Cookie csrfCookie = null;
for (Cookie cookie : cookieStore.getCookies()) {
    if (cookie.getName() == "csrftoken") {
        csrfCookie = cookie;
        break;
    }
}

if (csrfCookie == null) {
    throw new NullPointerException("CSRF cookie not found!");
}

return csrfCookie;

请注意,您需要 org.apache.http.client 中的 CookieStore

POST 请求:

HttpClient httpClient = new DefaultHttpClient();
HttpContext localContext = new BasicHttpContext();
HttpPost httpPost = new HttpPost(url);

// Prepare the cookie store to receive cookies.
CookieStore cookieStore = new BasicCookieStore();
cookieStore.addCookie(csrfCookie);
httpPost.setHeader("Referer", url);
httpPost.setHeader("X-CSRFToken", csrfCookie.getValue());
localContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);

MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
builder.addTextBody("email", emailAddressToReset);
httpPost.setEntity(builder.build());

HttpResponse httpResponse = httpClient.execute(httpPost, localContext);
if (httpResponse.getStatusLine().getStatusCode() != 200) {
    throw new Exception("Could not reset password!");
}

Toast.makeText(context, "Password reset requested! Please check your email inbox!", Toast.LENGTH_LONG).show();