If you happen to work, like me, on a project that makes use of both the Play framework and AngularJS, you may at some point need to read some data from the Play session in your AngularJS application. Play uses a client-side session, which makes sharing the data with client-side applications easy.
In order to access the session data on the client-side, you’ll need the following:
1. Allow the Play session to be read by javascript
In application.conf
, set the session.httpOnly
flag to false:
1 2 3 |
# Allow the session cookie to be accessed from JavaScript libraries session.httpOnly=false |
2. Enable the $cookies service in AngularJS
You’ll need to use the ngCookies
module (provided by angular-cookies.js
– make sure you have loaded this file):
1 2 |
angular.module('myApp', ['ngCookies']); |
This gives you access to the $cookies
service.
3. Decypher the cookie data
Play encodes the session into a single string, so you’ll need to decode it:
1 2 3 4 5 6 7 8 9 10 |
// read Play session cookie var rawCookie = $cookies['PLAY_SESSION']; var rawData = rawCookie.substring(rawCookie.indexOf('-') + 1); var session = {}; _.each(rawData.split("\u0000"), function(rawPair) { var pair = rawPair.split(':'); session[pair[0]] = pair[1]; }); console.log(session); |
The code above makes use of underscore.js, if you don’t use it yet, I can only recommend using it.
That’s it! You now can make the session data available throughout your Angular application, for example by providing a service:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
angular.module('admin.services', ['ngCookies']). factory('session', ['$cookies', function($cookies) { // read Play session cookie var rawCookie = $cookies['PLAY_SESSION']; var rawData = rawCookie.substring(rawCookie.indexOf('-') + 1); var session = {}; _.each(rawData.split("\u0000"), function(rawPair) { var pair = rawPair.split(':'); session[pair[0]] = pair[1]; }); return session; }]); |
Update: for Play 2.1.3 and above, the cookie encoding changed, and is now:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
angular.module('admin.services', ['ngCookies']). factory('session', ['$cookies', function($cookies) { // read Play session cookie var rawCookie = $cookies['PLAY_SESSION']; var rawData = rawCookie.substring(rawCookie.indexOf('-') + 1, rawCookie.length -1); var session = {}; _.each(rawData.split("&"), function(rawPair) { var pair = rawPair.split('='); session[pair[0]] = pair[1]; }); return session; }]) |
Comments 7
Is there a reason you prefer _.each over angular.forEach?
And when you use the Play session cookie, doesn’t this make you vulnerable to CRSF attacks?
Author
Good point about CSRF, of course you should use appropriate mechanisms (token generation) – but that holds also true if the cookie is not exposed to javascript, does it not? About _.each against angular.forEach, there’s no particular reason I prefer it other than it being very short (_) and having already made use of underscore.js in the project (so I didn’t need to add it as an extra dependency).
We just create a different cookie and set the session id to the cookie’s values, this way the session cookie is still httpOnly and no need for parsing; later you can stamp the new cookie with something other than session id.
Small tip, use a cookie called XSRF formyour token, it makes the whole authorization stuff easier, because Angular picks it up automatically.
MariusU do hv example for XSRF ?
just what i needed – thanks
Hi… how are you?
Good job about your post.
But, let me ask you somthing.
What could happen if this approach doesn’t work? The console about the cookie is empty – but if I look the cookie on network call, it is there.
my application.conf
Allow the session cookie to be accessed from JavaScript libraries
session.httpOnly=false
my service
define([
"angular",
"angular-cookies",
"app-services",
"app-sessao",
"gumga-class"
],
function(angular, ngCookies, services, sessao, clazz) {
"use strict";
});