[英]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 令牌值...
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.