我真的很困。这就是我想要做的。
任何地方都适用。将其投入生产后,就会开始出现CSRF错误。这就是一切的方法。
我看到了所有答案,包括从关闭CSRF到允许所有操作的所有内容。我想这样做是正确的,而不仅仅是关闭事物并打开所有内容并最终出现安全漏洞。
所以,这就是我所拥有的。
已安装: django-cors-headers django-rest-framework drf嵌套路由器 ...和其他人
我的api运行在api.websitename.com,而Vue.js应用程序运行在websitename.com。
GET请求的效果很好。 OPTION请求似乎有效。
任何冒险的请求均不起作用。
对于我的CORS,我先安装了'corsheaders.middleware.CorsMiddleware',
,然后安装了MIDDLEWARE
。
然后我的CORS设置是:
CORS_ALLOW_CREDENTIALS = True
CORS_ORIGIN_WHITELIST = (
'*.websitename.com',
)
我的CSRF设置是:
CSRF_TRUSTED_ORIGINS = [
"api.websitename.com",
]
无论我如何使用它们,最终都会遇到CSRF令牌错误。
我已经尝试过在Vue App.vue文件中执行以下操作的方法:
mounted () {
this.getCSRFToken()
},
methods: {
getCSRFToken () {
return axios.get('token/').then(response => {
axios.defaults.headers.common['x-csrftoken'] = Cookies.get('csrftoken')
}).catch(error => {
return Promise.reject(error.response.data)
})
}
}
这个想法是,一旦APP在浏览器中加载,我就会获得CSRF令牌。但是即使如此,当应用程序尝试执行除GET或OPTION以外的任何操作时,我仍会遇到CSRF令牌错误。
这是在您有古玩的情况下返回令牌的视图:
class CSRFTokenView(APIView):
permission_classes = (permissions.AllowAny,)
@method_decorator(ensure_csrf_cookie)
def get(self, request):
return HttpResponse()
我意识到我可能在这里混了很多问题,但是欢迎提出任何可能帮助我解决问题的建议。
答案 0 :(得分:2)
首先要使用SessionAuthentication:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.SessionAuthentication',
)
}
这将强制执行CSRF,但匿名用户除外(稍后将对此进行详细介绍)。对于浏览器前端,最简单的解决方案是将(浏览器)前端和后端都放在同一个域中-这样可以避免CORS-如上面的注释所建议。如果您还有其他客户端,则只需使用令牌(DRF令牌或JWT)-但是由于XSS攻击的危险,这些令牌对于浏览器使用是不安全的(将令牌存储在localStorage中本质上是不安全的)。
在使用axios时,CSRF设置非常简单:
import axios from 'axios'
axios.defaults.xsrfHeaderName = 'X-CSRFToken'
axios.defaults.xsrfCookieName = 'csrftoken'
因此,您应该与CSRF进行安全会话。几乎。要引用上面的链接页面:
警告:创建登录页面时,请始终使用Django的标准登录视图。这将确保您的登录视图受到适当的保护。
REST框架中的CSRF验证与标准Django的工作原理略有不同,这是因为需要支持对同一视图的基于会话和基于非会话的身份验证。这意味着只有经过身份验证的请求才需要CSRF令牌,而匿名请求可能没有CSRF令牌就可以发送。此行为不适用于应始终应用CSRF验证的登录视图。
这很棘手-您要么只使用Django服务器端视图,这会使您的SPA设计有些复杂,要么在DRF中重新创建登录名和其他身份验证视图,但需要注意的是使用@csrf_protect方法装饰器在这些“匿名”视图上实施CSRF。显然,这样的视图将对使用令牌的客户端造成破坏,因此您可能希望为此使用不同的终结点(可能重新使用相同的基类)。因此,您的浏览器登录名使用 / auth / browser / login / 和您的移动登录名 / auth / mobile / login / ,前者使用 @csrf_protect 。
在研究contrib auth源代码后,应仔细地重新创建登录名和其他auth视图。对于原始要求,我建议使用django-rest-auth和django-all-auth之类的预先存在的解决方案。但是django-rest-auth软件包不是为浏览器前端设计的很好,并且会强制使用令牌生成,此外,您还需要如上所述包装视图。另一方面,all-auth为JS客户端提供AJAX响应,可能是更好的选择。
答案 1 :(得分:0)
到目前为止,解决此问题的最简单方法是为同一域中的所有内容提供服务。您可以将CDN或代理直接/api
呼叫到一台服务器,其余的直接到前端服务器。这样,完全不必担心CORS。
要使其正常工作,我认为您只是在AXIOS配置中缺少withCredentials = true
。 Django要求在未设置withCredentials
的情况下发送CSRF cookie,并且不能通过跨源请求发送cookie。
axios.interceptors.request.use(function (config) {
config.withCredentials = true
return config
})
Djano的SESSION_COOKIE_DOMAIN
可能是另一个可能缺少的设置。您应该这样设置:
SESSION_COOKIE_DOMAIN=".mywebsite.com"
第一个点很重要,因为它告诉Django,然后告诉网络浏览器将cookie用于*.mywebsite.com
,包括api.mywebsite.com
。
如果所有操作仍然失败,我建议在Django的CSRF中间件上设置一个断点,以查看使它工作的缺失之处。