AngularJS Authentication Patterns

  • 7,464 views
Uploaded on

There are so many options to implement basic and more advanced authentication techniques in AngularJS applications. Here's some food for thought on using the full potential of Angular including custom …

There are so many options to implement basic and more advanced authentication techniques in AngularJS applications. Here's some food for thought on using the full potential of Angular including custom services, route resolvers and http interceptors to handle basic authentication, role based authentication authentication errors and a first approach to feature stripping based on user permissions.

Presented at the Seattle AngularJS Meetup on March 19, 2014 - http://www.meetup.com/AngularJS-SEA/events/169192362/

More in: Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
7,464
On Slideshare
0
From Embeds
0
Number of Embeds
3

Actions

Shares
Downloads
94
Comments
0
Likes
18

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. A U T H E N T I C AT I O N PAT T E R N S A N G U L A R J S
  • 2. J o s h S c h u m a c h e r @ j o s h s c h u m a c h e r h t t p s : / / p l u s . g o o g l e . c o m / + J o s h S c h u m a c h e r s H a s O ff e r s
  • 3. A U T H E N T I C AT I O N PAT T E R N S
  • 4. I N I T I A L C O N S I D E R AT I O N S • HTTPS is a must • Trust no one • Even if you have awesome frontend security, do it on the backend too • Cookies vs Tokens • Token in params vs headers
  • 5. routes = { '/' : { 'redirectTo' : '/login', 'public' : true }, ! '/about' : { 'templateUrl' : '/components/about/about.html', 'controller' : angular.noop, 'public' : true }, ! '/dashboard' : { 'templateUrl' : '/components/dashboard/dashboard.html', 'controller' : 'dashboard.dashboard' }, ! '/manage' : { 'templateUrl' : '/components/admin/manage.html', 'controller' : 'admin.manage', 'role' : ['admin'] }, ! '/login' : { 'templateUrl' : '/components/account/login.html', 'controller' : 'account.login', 'public' : true, 'resolve' : { data : ['authService', '$location', function(authService, $location) { if (authService.isLoggedIn) { $location.path('/dashboard'); } }] } } };
  • 6. defaultResolvers.userAuthenticated = [ '$q', 'authService', function($q, authService) { var deferred = $q.defer(); ! var reject = function() { deferred.reject('login_required'); }; ! authService.getAuthPromise().then(function(result) { deferred.resolve(result); }, reject); ! return deferred.promise; } ];
  • 7. _(routes).each(function(params, location) { params.location = location; params.caseInsensitiveMatch = true; params.reloadOnSearch = false; ! var resolve = angular.extend({}, defaultResolvers, params.resolve || {}); ! if (params.public) { delete resolve.userAuthenticated; } ! // Add role based resolver if (params.role) { resolve.role = ['$q', 'rolesService', function($q, rolesService) { var deferred = $q.defer(); ! if (rolesService.hasRoles(params.role)) { deferred.resolve(); } else { deferred.reject('missing_role'); } }]; } ! params.resolve = resolve; ! $routeProvider.when(location, params); });
  • 8. // handle logout $routeProvider.when('/logout', { resolve : { data : ['authService', function(authService) { authService.logout(); }] } }); ! // otherwise we redirect everything to login $routeProvider.otherwise({ 'redirectTo' : '/login', });
  • 9. $rootScope.$on('$routeChangeError', function(event, current, previous, rejection) { switch (rejection) { case 'login_required': authService.logout(); break; default: $log.error('router', 'Unhandled route resolver rejection', rejection); } });
  • 10. app.config(function ($httpProvider) { $httpProvider.interceptors.push(['$rootScope', function ($rootScope) { return { responseError : function(response) { if (response.status === 401) { $rootScope.$broadcast('http_status_401'); } ! return $q.reject(response); } } }]); });
  • 11. U S I N G I N T E R C E P T O R S T O S C R U B F E AT U R E S <div data-keep="account:manage"> Some sort of feature that you need the account->manage permission to see/use </div>
  • 12. app.config(function ($httpProvider) { $httpProvider.interceptors.push(['$injector', function ($injector) { return { response : function(response) { if (response.headers('content-type') === 'text/html' || response.config.url.match(/.html$/)) { var userPermissions = $injector.get('userPermissions'); ! var $responseData = $(response.data); ! $responseData.find('[data-keep]').each(function() { if (!userPermissions.hasPermission($(this).data('keep'))) { $(this).remove(); } else { $(this).removeAttr('data-keep'); } }); ! // taking special care to do outerHTML so that scripts aren't lost; // doing $('<div>').append($responseData).html() ends up stripping out scripts in HTML views var html = []; _.each($responseData, function($el) { if ($el && $el.outerHTML) { html.push($el.outerHTML); } }); response.data = html.join(''); } return response; } } } }]); });
  • 13. A F E W TA K E A WAY S • Maintain application auth state in a service • Route Resolvers • HTTP Interceptors • Handle authentication errors • Feature stripping