recover from bad CSRF tokens without requiring a hard refresh of the browser

This commit is contained in:
Sam 2013-08-27 15:56:12 +10:00
parent bec463564f
commit c4a0152dc6
5 changed files with 16 additions and 9 deletions

View File

@ -132,13 +132,13 @@ Discourse = Ember.Application.createWithMixins(Discourse.Ajax, {
}); });
// Add a CSRF token to all AJAX requests // Add a CSRF token to all AJAX requests
var csrfToken = $('meta[name=csrf-token]').attr('content'); Discourse.csrfToken = $('meta[name=csrf-token]').attr('content');
console.log(Discourse.csrfToken);
$.ajaxPrefilter(function(options, originalOptions, xhr) { $.ajaxPrefilter(function(options, originalOptions, xhr) {
if (!options.crossDomain) { if (!options.crossDomain) {
// This may be delay set xhr.setRequestHeader('X-CSRF-Token', Discourse.csrfToken);
csrfToken = csrfToken || $('meta[name=csrf-token]').attr('content');
xhr.setRequestHeader('X-CSRF-Token', csrfToken);
} }
}); });

View File

@ -56,6 +56,12 @@ Discourse.Ajax = Em.Mixin.create({
var oldError = args.error; var oldError = args.error;
args.error = function(xhr) { args.error = function(xhr) {
// note: for bad CSRF we don't loop an extra request right away.
// this allows us to eliminate the possibility of having a loop.
if (xhr.status === 403 && xhr.responseText == "['BAD CSRF']") {
Discourse.csrfToken = null;
}
// If it's a parseerror, don't reject // If it's a parseerror, don't reject
if (xhr.status === 200) return args.success(xhr); if (xhr.status === 200) return args.success(xhr);
@ -73,12 +79,11 @@ Discourse.Ajax = Em.Mixin.create({
// For cached pages we strip out CSRF tokens, need to round trip to server prior to sending the // For cached pages we strip out CSRF tokens, need to round trip to server prior to sending the
// request (bypass for GET, not needed) // request (bypass for GET, not needed)
var csrfToken = $('meta[name=csrf-token]').attr('content'); if(args.type && args.type !== 'GET' && !Discourse.csrfToken){
if(args.type && args.type !== 'GET' && !csrfToken){
return Ember.Deferred.promise(function(promise){ return Ember.Deferred.promise(function(promise){
$.ajax(Discourse.getURL('/session/csrf')) $.ajax(Discourse.getURL('/session/csrf'))
.success(function(result){ .success(function(result){
$('head').append('<meta name="csrf-token" content="' + result.csrf + '">'); Discourse.csrfToken = result.csrf;
performAjax(promise); performAjax(promise);
}); });
}); });

View File

@ -22,7 +22,7 @@ class ApplicationController < ActionController::Base
unless is_api? unless is_api?
super super
clear_current_user clear_current_user
raise Discourse::CSRF render text: "['BAD CSRF']", status: 403
end end
end end

View File

@ -67,7 +67,7 @@ class SessionController < ApplicationController
end end
def destroy def destroy
session[:current_user_id] = nil reset_session
cookies[:_t] = nil cookies[:_t] = nil
render nothing: true render nothing: true
end end

View File

@ -83,6 +83,8 @@ class Users::OmniauthCallbacksController < ApplicationController
# log on any account that is active with forum access # log on any account that is active with forum access
if Guardian.new(user).can_access_forum? && user.active if Guardian.new(user).can_access_forum? && user.active
log_on_user(user) log_on_user(user)
# don't carry around old auth info, perhaps move elsewhere
session[:authentication] = nil
@data.authenticated = true @data.authenticated = true
else else
if SiteSetting.invite_only? if SiteSetting.invite_only?