Skip to content

Commit

Permalink
Work on authentication
Browse files Browse the repository at this point in the history
Closes #100, Closes #187

When a login is required a user is now redirected to rails login page.
Redirect back on successful login is blocked by QutEcoacoustics/baw-server#205

Also configured a new HTTP interceptor to block all out going HTTP requests until a HTTP auth token has been retrieved.
There's no timeout on this block.

Also removed old HTTP interceptor that worked with CSRF tokens.
Angular will use its own token stuff when deployed to staging/prod.
  • Loading branch information
atruskie committed Jun 1, 2015
1 parent d12d388 commit 70c3865
Show file tree
Hide file tree
Showing 7 changed files with 312 additions and 268 deletions.
9 changes: 7 additions & 2 deletions src/baw.configuration.tpl.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,9 @@ angular.module('bawApp.configuration', ['url'])
contactUs: '/contact_us',
disclaimers: '/disclaimers',
credits: '/credits',
ethicsStatement: '/ethics_statement'
ethicsStatement: '/ethics_statement',
login: "/my_account/sign_in"

}
},
site: {
Expand Down Expand Up @@ -207,6 +209,9 @@ angular.module('bawApp.configuration', ['url'])
)
.constant("conf.constants", {
namespace: "baw-client",
rails: {
loginRedirectQsp: "user_redirect_to"
},
localization: {
dateTimeFormat: "YYYY-MMM-DD HH:mm:ss",
dateTimeShortFormat: "YYYY-MMM-DD HH:mm",
Expand Down Expand Up @@ -243,7 +248,7 @@ angular.module('bawApp.configuration', ['url'])
},
supported: {
msie: 10,
firefox: 30,
firefox: 36,
chrome: 30,
safari: 5.1,
opera: 23,
Expand Down
19 changes: 14 additions & 5 deletions src/components/directives/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ angular.module('angular-auth', ['http-auth-interceptor'])
* and will remove that class, so CSS will remove loading image and show app content.
* It is also responsible for showing/hiding login form.
*/
.directive('bawAuth', function () {
.directive('bawAuth', ["$window", "$location", "$url", "conf.paths", "conf.constants",
function ($window, $location, $url, paths, constants) {
return {
restrict: 'AC',
link: function (scope, elem, attrs) {
Expand Down Expand Up @@ -35,6 +36,16 @@ angular.module('angular-auth', ['http-auth-interceptor'])
};

scope.$on('event:auth-loginRequired', function () {
// temporary hack - send login requests to rails

var url = paths.api.links.loginAbsolute;

// get current url to redirect to
var obj ={};
obj[constants.rails.loginRedirectQsp] = $location.absUrl();
url = $url.formatUri(url, obj);
$window.location = url;
/*
// TODO: add extra checks to stop multiple animations
var isOpen = isLoginBoxOpen();
Expand All @@ -45,7 +56,7 @@ angular.module('angular-auth', ['http-auth-interceptor'])
main.hide();
});
}
}*/
});

scope.$on('event:auth-loginConfirmed', function () {
Expand All @@ -69,9 +80,7 @@ angular.module('angular-auth', ['http-auth-interceptor'])
});
}
};
})

;
}]);



172 changes: 113 additions & 59 deletions src/components/services/angularHttpAuth.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,76 +4,130 @@
* License: MIT
* https://github.com/witoldsz/angular-http-auth/tree/gh-pages
*/
angular.module("http-auth-interceptor", [])
angular
.module("http-auth-interceptor", [])
.provider(
'authService',
function () {
/**
* Holds all the requests which failed due to 401 response,
* so they can be re-requested in future, once login is completed.
*/
var buffer = [];

.provider('authService', function () {
/**
* Holds all the requests which failed due to 401 response,
* so they can be re-requested in future, once login is completed.
*/
var buffer = [];
/**
* Required by HTTP interceptor.
* Function is attached to provider to be invisible for regular users of this service.
*/
function pushToBuffer(type, config, deferred) {
buffer.push({
type: type,
config: config,
deferred: deferred
});
}
this.pushToBuffer = pushToBuffer;

/**
* Required by HTTP interceptor.
* Function is attached to provider to be invisible for regular users of this service.
*/
this.pushToBuffer = function (config, deferred) {
buffer.push({
config: config,
deferred: deferred
});
};
this.$get = ['$rootScope', '$injector', function ($rootScope, $injector) {
var $http; // initialized later because of circular dependency problem
function retryRequest(config, deferred, $http) {
config.headers["Authorization"] = $http.defaults.headers.common["Authorization"];

this.$get = ['$rootScope', '$injector', function ($rootScope, $injector) {
var $http; // initialized later because of circular dependency problem
function retry(config, deferred) {
$http = $http || $injector.get('$http');
$http(config).then(function (response) {
deferred.resolve(response);
});
}
deferred.resolve(config);
}

function retryAll() {
for (var i = 0; i < buffer.length; ++i) {
retry(buffer[i].config, buffer[i].deferred);
}
buffer = [];
}
function retryResponse(config, deferred) {
$http(config).then(function (response) {
deferred.resolve(response);
});
}

return {
loginConfirmed: function () {
console.info("authService::event:auth-loginConfirmed");
$rootScope.$broadcast('event:auth-loginConfirmed');
function retryAll() {
$http = $http || $injector.get("$http");

retryAll();
}
};
}];
})
for (var i = 0; i < buffer.length; ++i) {
switch (buffer[i].type) {
case "request":
retryRequest(buffer[i].config, buffer[i].deferred, $http);
break;
case "response":
retryResponse(buffer[i].config, buffer[i].deferred);
break;
default:
throw new Error ("invalid switch case");
}
}
buffer = [];
}

return {
loginConfirmed: function () {
console.info("authService::event:auth-loginConfirmed - flushing buffer, request count:", buffer.length);
$rootScope.$broadcast('event:auth-loginConfirmed');

retryAll();
},
pushRequestToBuffer: pushToBuffer.bind(null, "request"),
pushResponseToBuffer: pushToBuffer.bind(null, "response")
};
}];
})
/**
* $http interceptor.
* On 401 response - it stores the request and broadcasts 'event:angular-auth-loginRequired'.
*/
.factory("authHttpInterceptor",
["authService", "$rootScope", "$q",
function (authServiceProvider, $rootScope, $q) {
return {
'responseError': function error(response) {
if (response.status === 401) {
var deferred = $q.defer();
authServiceProvider.pushToBuffer(response.config, deferred);
.factory(
"authHttpInterceptor",
[
"authService",
"$rootScope",
"$q",
"conf.paths",
function (authService, $rootScope, $q, paths) {
return {
'request': function request(config) {
// if an auth token is present
if (config.headers["Authorization"]) {
// don't do anything
return config;
}

// if not API call (i.e. JSON) ///config.headers["Accept"] === "application/json" &&
// if the route to actually sign in!
// or if requesting a cached resource (usually a template)
if (config.url.indexOf(paths.api.routes.security.signIn) >= 0 ||
config.cached === true) {
// then continue unimpeded
console.debug("authHttpInterceptor:request:Not deferring request to wait for auth credentials", config.url);
return config;
}

// otherwise, an auth token is not available
// queue the request up
console.warn("authHttpInterceptor:request: deferring request, auth token not available", config.url);
var deferred = $q.defer();
authService.pushRequestToBuffer(config, deferred);

console.info("authService::event:auth-loginRequired");
$rootScope.$broadcast('event:auth-loginRequired');
return deferred.promise;
}
// otherwise
return $q.reject(response);
}
};
}])
if (!$rootScope.logInPending) {
$rootScope.$broadcast('event:auth-loginRequired');
}

return deferred.promise;
},
'responseError': function error(response) {
if (response.status === 401) {
var deferred = $q.defer();
authService.pushResponseToBuffer(response.config, deferred);

console.info("authService::event:auth-loginRequired");
$rootScope.$broadcast('event:auth-loginRequired');
return deferred.promise;
}
// otherwise
return $q.reject(response);
}
};
}])
.config(['$httpProvider', function ($httpProvider) {
$httpProvider.interceptors.push("authHttpInterceptor");
}]);
$httpProvider.interceptors.push("authHttpInterceptor");
}]);
Loading

0 comments on commit 70c3865

Please sign in to comment.