【问题标题】:Django Angular Authentication CSRF cached templateDjango Angular Authentication CSRF 缓存模板
【发布时间】:2014-01-06 22:48:53
【问题描述】:

我在成功登录和注销后尝试登录时收到状态代码 403。

客户端用 Angular 编写,服务器端用 Django。

如下:

  1. 客户端请求 url '/' 使用所有必需的静态文件(角度、引导程序、jQuery 源和我定义的角度源)获取主 HTML 模板 <div ng-view></div> 将插入更多模板的标签。
  2. 通过 $location 服务被重定向到 url '/#/login'
  3. $routeProvider 中的这条规则在'/#/login' 被命中后执行: $routeProvider.when('/login', { templateUrl: 'login.html' });
  4. 'login.html' 由 django 视图提供服务,用于登录的表单呈现给用户
  5. 用户登录成功并提供正确的凭据
  6. 然后用户通过单击一个按钮注销,该按钮触发'$http.get( '/logout/' );',然后重定向到url '/#/login'
  7. 这就是问题所在。当用户填写凭证表单并发送'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');
            }

        });
}]);

【问题讨论】:

  • 能否请您粘贴来自 chrome 开发工具或类似工具的请求和响应标头。
  • @JoakimB 无论有没有 Django-template-system,您仍然需要 CSRF 令牌/cookie 来与 API 交互,因此模板系统与我遇到的问题没有任何关系。
  • 我没有说这与问题有关,这是一个简单的提示 :) 请求/响应标头仍然有助于解决发生的问题

标签: ajax django angularjs csrf django-csrf


【解决方案1】:

一种解决方案是直接从 cookie 中读取当前新鲜的 csrftoken,然后使用 javascript 更新陈旧的 cookie。

var fresh_token = document.cookie.match('csrftoken=([a-zA-Z0-9]{32})

【讨论】:

    【解决方案2】:

    我通过在$routeChangeStart 事件中设置X-CSRFTOKEN 标头解决了这个问题。 我不完全知道 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');
                    }
    
                });
    }]);
    

    这与从$templateCache 中删除'login.html' 模板一起使用。

    除了使用$templateCache 服务在客户端删除模板之外,还可以将您的服务器设置为提供模板并设置以下标头:

    Cache-Control: no-cache, no-store, must-revalidate
    Pragma       : no-cache
    Expires      : 0
    

    解决此问题的另一种方法是简单地强制页面刷新,但是我不喜欢这种方法,因为这不是支持单页应用程序的方法。 :)

    【讨论】:

      【解决方案3】:

      这可能是缓存问题。尝试将 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")
      
      ...
      

      【讨论】:

      • 也没用
      猜你喜欢
      • 1970-01-01
      • 2017-10-25
      • 1970-01-01
      • 2014-03-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-03
      • 2012-03-29
      相关资源
      最近更新 更多