如果我的前端应用不是由Django提供服务,我如何获得Django的auth contrib视图的CSRF令牌?

t8e9dugd  于 2023-01-06  发布在  Go
关注(0)|答案(1)|浏览(169)

bounty将在6天后过期。回答此问题可获得+100的声誉奖励。Dave正在寻找来自声誉良好的来源的答案

我使用Django 3.1.1和Django的auth contrib模块来管理用户。我没有使用Django模板,而是创建了一个Django API应用程序来响应来自React前端的请求。我在www.example.com文件中有这个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']

我在我的www.example.com文件中设置了这个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令牌,以便在提交密码重置表单时可以将其提交回来?

h43kikqp

h43kikqp1#

    • 免责声明**

这个答案在JS/ReactJS中没有实现,但是它有关于如何实现它们的一般说明。
如果您访问了TemplateResponse渲染的有效视图,Django将返回CSRF令牌和cookie。要获得CSRF令牌,您需要发送HTTP GET请求到相同的URL(response may look like this)。完成请求后,您将在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'}

相关问题