我在成功登录并注销后尝试登录时收到状态码403。
客户端用Angular编写,服务器端用Django编写。
具体如下:
'/'
使用所有必需的静态文件(angular,bootstrap,jQuery源和我定义的角度源)获取主HTML模板
<div ng-view></div>
标记将插入更多模板。'/#/login'
$routeProvider
的此规则会在'/#/login'
被点击后执行:
$routeProvider.when('/login', {
templateUrl: 'login.html'
});
'login.html'
由django视图提供,用于登录的表单呈现给用户'$http.get(
'/logout/'
);'
,然后重定向到网址'/#/login'
'POST'
请求时,将返回403。我认为是这样,因为这个路由只是通过角度来完成的,因为已经请求了'login.html'
模板,它已经被捕获并且可以在没有命中后端的情况下提供服务,但是在注销后当前拥有的CSRF cookie是陈旧的,所以这就是为什么我得到403.所以我试图删除该模板:logout: function(){
var forceLoginTemplateRequest = function(){
if( $templateCache.get('login.html') !== 'undefined'){
$templateCache.remove('login.html');
}
};
var responsePromise = $http.get(
urls.logout
);
responsePromise.success(forceLoginTemplateRequest);
return responsePromise;
}
执行此操作后,我可以在注销后始终看到客户端请求'login.html'
模板,因此我认为在从后端提供该模板时我可以提供CSRF cookie:
#urls.py
urlpatterns = patterns(
'',
...
url(r'^$', serve_home_template),
url(r'^login.html$', serve_login_template),
url(r'^login/', login_view, name='login'),
url(r'^logout/', logout_view, name='logout'),
...
)
#views.py
@ensure_csrf_cookie
def serve_login_template(request):
return render(request, "login.html")
@ensure_csrf_cookie
def serve_home_template(request):
return render(request, 'home.html')
但它仍然不起作用,我在登出后尝试登录时收到403。我管理它的唯一方法是简单地刷新页面,以便从后端再次请求每个文件,无论是模板还是源文件,并使用它们更新CSRF cookie。
这是我的应用程序的运行部分,用于确保每次请求都发送CSRF cookie:
mainModule.run(['$http','$cookies', '$location', '$rootScope', 'AuthService', '$templateCache',
function($http, $cookies, $location, $rootScope, AuthService, $templateCache) {
$http.defaults.headers.common['X-CSRFToken'] = $cookies.csrftoken;
$rootScope.$on( "$routeChangeStart", function(event, next, current) {
if ( !(AuthService.isLoggedIn() == "true")){
$location.path('/login');
}
});
}]);
答案 0 :(得分:0)
这可能是缓存问题。尝试将never_cache
装饰器添加到您的所有视图中:
from django.views.decorators.cache import never_cache
...
@ensure_csrf_cookie
@never_cache
def serve_login_template(request):
return render(request, "login.html")
...
答案 1 :(得分:0)
我通过在X-CSRFTOKEN
事件中设置$routeChangeStart
标头来解决此问题。
我并不完全知道 module.run阶段是如何工作的,但似乎当它内部定义的某个事件发生时,在该事件的处理程序体之外定义的所有内容都不会被执行。
mainModule.run(['$http','$cookies', '$location', '$rootScope', 'AuthService',
function($http, $cookies, $location, $rootScope, AuthService) {
$http.defaults.headers.common['X-CSRFToken'] = $cookies.csrftoken;
$rootScope.$on( "$routeChangeStart", function(event, next, current) {
// Added this line
$http.defaults.headers.common['X-CSRFToken'] = $cookies.csrftoken;
if ( !(AuthService.isLoggedIn() == "true")){
$location.path('/login');
}
});
}]);
这与从'login.html'
删除$templateCache
模板一起使用。
除了使用$templateCache
服务在客户端删除模板外,还可以将服务器设置为提供模板并设置以下标题:
Cache-Control: no-cache, no-store, must-revalidate
Pragma : no-cache
Expires : 0
解决这个问题的另一种方法是简单地强制页面刷新,但是我不喜欢这种方法,因为这不是专业的单页面应用方法。 :)
答案 2 :(得分:0)
一种解决方案可能是直接从cookie中读取当前的新鲜csrftoken,然后使用javascript更新陈旧的cookie。
var fresh_token = document.cookie.match('csrftoken=([a-zA-Z0-9]{32})