load balancing
sticky sessions on reverse-proxy
e.g. jvmRoute on tomcat
backend restart = session lost
share-nothing architecture
REST
no Sessions
no Cookies
implies that every request must carry on authentication
Authorization: Basic YWRtaW46YWRtaW4=
backends can be restarted freely
Moving the session in the browser
backend: a restful web service
resteasy
maven + JBoss AS
HTTPS
basic auth
JSON + CSV mediatypes
frontend: angularJS
maven + webjars + JBoss AS
// hiding how we store the auth data
app.service('AuthContext', function($localStorage) {
this.put = function(authentication) {
localStorage.authentication = authentication;
};
this.reset = function() {
delete $localStorage.authentication;
};
this.get = function() {
return $localStorage.authentication;
};
return this;
});
// in-memory login/logout
// login
AuthContext.put({ token: basicAuthToken });
// logout
AuthContext.reset();
http interceptors
(similar to servlet filters, spring mvc interceptor, etc)
// put 'Authorization' header on each outgoing request
$httpProvider.interceptors.push(function($rootScope, AuthContext){
return {
'request' : function(request) {
var auth = AuthContext.get();
if (auth) {
request.headers.Authorization = auth.token;
}
return request;
}
}
});
// postpone session expiry until a 'session.keepalive' event is produced
app.run(function($rootScope, $timeout, AuthContext) {
var sessionTimeout = moment.duration(10, 'minutes');
var logout = function() {
AuthContext.reset();
};
var promise = $timeout(logout, sessionTimeout.asMilliseconds());
$rootScope.$on("session.keepalive", function() {
$timeout.cancel(promise);
promise = $timeout(logout, sessionTimeout.asMilliseconds());
});
});
// a 'session.keepalive' event producer
$httpProvider.interceptors.push(function($rootScope) {
return {
'request' : function(request) {
$rootScope.$broadcast("session.keepalive");
return request;
}
};
});