簡體   English   中英

如果 Django 不提供我的前端應用程序,我如何為 Django 的 auth contrib 視圖獲取 CSRF 令牌?

[英]How do I get a CSRF token for Django's auth contrib views if my frontend app is not served by Django?

我正在使用 Django 3.1.1 和 Django 的 auth contrib 模塊來管理用戶。 我沒有使用 Django 模板,而是創建一個 Django API 應用程序來響應來自我的 React 前端的請求。 我的 settings.py 文件中有這個

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'directory.middleware.extend_token_response.ExtendTokenResponse'
]

#CORS_ORIGIN_ALLOW_ALL = True

ALLOWED_HOSTS = ['127.0.0.1', 'localhost', 'dev.mywebsite.com', 'prod.mywebsite.com', 'map.mywebsite.com']

CORS_ORIGIN_WHITELIST = [
    'http://localhost:3000', 'http://localhost:3001', 'http://127.0.0.1:3000', 'http://127.0.0.1:3001'
]

CORS_EXPOSE_HEADERS = [
    'Refresh-Token', 'Content-Type', 'Authorization', 'X-CSRFToken'
]
CORS_ALLOW_CREDENTIALS = True
CSRF_TRUSTED_ORIGINS = ['localhost', '127.0.0.1']

我在我的 views.py 文件中設置了這個

class ResetPasswordView(SuccessMessageMixin, PasswordResetView):
    email_template_name = 'users/password_reset_email.html'
    subject_template_name = 'users/password_reset_subject'
    success_message = "We've emailed you instructions for setting your password, " \
                      "if an account exists with the email you entered. You should receive them shortly." \
                      " If you don't receive an email, " \
                      "please make sure you've entered the address you registered with, and check your spam folder."
    success_url = reverse_lazy('users-home')

    def post(self, request, *args, **kwargs):
        print("request data %s" % request.data)
        email = request.data.get('email')
        try:
            if User.objects.get(email=email).active:
                print("email: %s " % email)
                return super(ResetPasswordView, self).post(request, *args, **kwargs)
        except:
            # this for if the email is not in the db of the system
            return super(ResetPasswordView, self).post(request, *args, **kwargs)

在我的前端,我使用這個獲取代碼向我的后端提交密碼重置請求

  const handleFormSubmit = (e) => {
    e.preventDefault()
    const csrftoken = getCsrfToken();
    fetch(REACT_APP_PROXY + '/reset_password', {
      method: 'POST',
      headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json',
        'X-CSRFToken': csrftoken
      },
      body: JSON.stringify({username})
    }).then(resp => resp.json())
    .then(jsob => {
      if(!jsob.ok){
        console.log(jsob)
        setErrors(jsob)
      }
      if(jsob.token){
        sessionStorage.setItem('token', jsob.token)
        setRedirect(true)
      }
    })
  }

問題是,我第一次提交表單時沒有 CSRF 令牌,因為 Django 沒有為我的 React 應用程序提供服務(它由 Apache 提供)。 我如何從 Django 獲取 CSRF 令牌,以便我可以在提交密碼重置表單時將其提交回去?

免責聲明

這個答案在 JS/ReactJS 中沒有實現,但它有關於如何擁有它們的一般說明。


如果您訪問使用TemplateResponse呈現的有效視圖,Django 將返回帶有 cookies 的 CSRF 令牌。 要在您的案例中獲取 CSRF 令牌,您需要將HTTP GET請求發送到相同的 URL(響應可能如下所示)。 完成請求后,您將在 cookie 部分獲得 CSRF 令牌。

在這里,我用 Python 的requests庫演示了一個簡單的例子。

In [23]: import requests

In [24]: url = "http://127.0.0.1:1234/pwd-reset/"

In [25]: response = requests.get(url)

In [26]: response.status_code
Out[26]: 200

In [27]: response.cookies.get_dict()
Out[27]: {'csrftoken': 'PABeYmF2k7Pvzhzu2UgqB0P63Ann5WeKqsODLmpx8VUtQhdn1DbhFT1Gs52pOEO5'}

您可以通過像這樣定位 csrf 隱藏輸入來獲取 csrf 令牌值...

視圖.py

def CreditSaveView(request):
    if request.method == 'POST':
        creditform = CreditForm(request.POST)
        if creditform.is_valid():
            amt = request.POST['amt']
            tag = request.POST['tag']
            crs = request.POST['csrfmiddlewaretoken']
            CreditModel(amt=amt,tag=tag).save()
            return JsonResponse({'status':'done'})

在標簽中

<script>
    document.getElementById("creditbtn").addEventListener("click", function () {
        let id_amt = document.getElementById('id_amt').value;
        let id_tag = document.getElementById('id_tag').value;
        let crs = document.getElementsByName('csrfmiddlewaretoken')[0].value
        my_data = { csrfmiddlewaretoken: crs, amt: id_amt, tag: id_tag };

        console.log(my_data)

        $.ajax({
            url: "/creditsave/",
            method: "POST",
            data: my_data,
            // dataType: "json",
            success: function (data) {
                if (data.status == 'done') {
                    // document.getElementById('creditform').reset()

                    document.getElementsByTagName('form')[1].reset()
                }
            }
        });
    });
</script>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM