From 185805b6cb313944258aeda25b5738ee2d05b602 Mon Sep 17 00:00:00 2001 From: justinsa Date: Mon, 6 Mar 2017 23:18:08 -0600 Subject: [PATCH] Remove hard dependency on local.storage service Storage service is now defined during configuration and then dynamically injected when required. Tests have been updated to use local.storage for validation. This also removes the hard dependency on ngCookies that existed merely to satisfy local.storage service. --- README.md | 28 ++++++++++++--- angular-authentication-service.js | 57 +++++++++++++++++++++---------- package.json | 2 +- tests.js | 9 +++-- 4 files changed, 69 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index 2db3721..31fd4f8 100644 --- a/README.md +++ b/README.md @@ -8,9 +8,7 @@ An authentication and authorization helper service for Angular client applicatio ##Dependencies * AngularJS - http://angularjs.org - * Angular Cookies - ngCookies - * angular-local-storage-service - [local.storage]((https://github.com/justinsa/angular-local-storage-service)) -* lodash +* Lodash - http://lodash.com ##Basic Setup @@ -18,11 +16,30 @@ An authentication and authorization helper service for Angular client applicatio ```JAVASCRIPT var app = angular.module('yourApp', ['authentication.service']); ``` -2. Inject $authentication as a parameter in declarations that require it: +2. Configure a storage service to use with the authentication provider: +```JAVASCRIPT +app.config(['$authenticationProvider', function ($authenticationProvider) { + $authenticationProvider.configure({ + storageService: '$store' + }); +}]); +``` +3. Inject $authentication as a parameter in declarations that require it: ```JAVASCRIPT app.controller('yourController', function($scope, $authentication){ ... }); ``` +The ng-authentication-service was designed in tandem with the following projects: + +* https://github.com/justinsa/angular-local-storage-service + +The injected storage service must support the following API: + + 1. ```get(key)``` + 2. ```has(key)``` + 3. ```remove(key)``` + 4. ```set(key, value)``` + ##Configuration Options To override the default configuration options, configure the module with an options argument during application configuration and provide overrides for any of the following options. @@ -30,7 +47,8 @@ To override the default configuration options, configure the module with an opti ```JAVASCRIPT app.config(['$authenticationProvider', function ($authenticationProvider) { $authenticationProvider.configure({ - authCookieKey: null, + storageService: undefined, + authCookieKey: undefined, profileStorageKey: 'user.profile', onLoginRedirectPath: '/', onLogoutRedirectPath: '/', diff --git a/angular-authentication-service.js b/angular-authentication-service.js index 3540607..9348520 100644 --- a/angular-authentication-service.js +++ b/angular-authentication-service.js @@ -5,24 +5,23 @@ if (typeof angular === 'undefined') { factory( typeof _ === 'undefined' ? require('lodash') : root._, - require('angular'), - require('angular-cookies'), - require('ng-local-storage-service') + require('angular') ); } else { factory(root._, root.angular); } module.exports = 'ng-authentication-service'; } else if (typeof define === 'function' && define.amd) { - define(['lodash', 'angular', 'angular-cookies', 'ng-local-storage-service'], factory); + define(['lodash', 'angular'], factory); } else { factory(root._, root.angular); } -}(this, function (_, angular, ngCookies, localStorage, undefined) { +}(this, function (_, angular, undefined) { 'use strict'; - angular.module('authentication.service', ['ngCookies', 'local.storage']).provider('$authentication', function () { + angular.module('authentication.service', []).provider('$authentication', function () { var configuration = { - authCookieKey: null, + storageService: undefined, + authCookieKey: undefined, profileStorageKey: 'user.profile', onLoginRedirectPath: '/', onLogoutRedirectPath: '/', @@ -50,22 +49,44 @@ }; this.$get = [ - '$cookieStore', '$document', '$location', '$rootScope', '$store', '$window', - function ($cookieStore, $document, $location, $rootScope, $store, $window) { + '$document', '$injector', '$location', '$log', '$rootScope', '$window', + function ($document, $injector, $location, $log, $rootScope, $window) { + var storeService; + var storageService = function () { + if (storeService === undefined) { + if (!_.isString(configuration.storageService)) { + $log.error('No storageService configuration value provided'); + return undefined; + } + if (!$injector.has(configuration.storageService)) { + $log.error('No matching service registered in Angular: ', configuration.storageService); + return undefined; + } + storeService = $injector.get(configuration.storageService); + _.each(['get', 'has', 'remove', 'set'], function (methodName) { + if (!_.has(storeService, methodName)) { + $log.error('Matching service is missing method: ', methodName); + return undefined; + } + }); + } + return storeService; + }; + var authFunctions = { /** * returns true if there is a user profile in storage. */ isAuthenticated: function () { if (this.isAuthCookieMissing()) { - if ($store.has(configuration.profileStorageKey)) { + if (storageService().has(configuration.profileStorageKey)) { // The cookie is absent or expired but we still have the profile stored. // Clear the profile and broadcast logout to ensure the app updates. this.logoutConfirmed(); } return false; } - return $store.has(configuration.profileStorageKey); + return storageService().has(configuration.profileStorageKey); }, /** @@ -89,7 +110,7 @@ * example if you need to pass through details of the user that was logged in. */ loginConfirmed: function (data) { - $store.set(configuration.profileStorageKey, data); + storageService().set(configuration.profileStorageKey, data); configuration.reauthId = setInterval(configuration.reauthFunc, configuration.reauthTimeout); $rootScope.$broadcast('event:auth-loginConfirmed', data); if (_.isString(configuration.onLoginRedirectPath)) { @@ -119,7 +140,7 @@ * call this function to indicate that unauthentication was successful. */ logoutConfirmed: function () { - $store.remove(configuration.profileStorageKey); + storageService().remove(configuration.profileStorageKey); $window.clearInterval(configuration.reauthId); configuration.reauthId = null; $rootScope.$broadcast('event:auth-logoutConfirmed'); @@ -156,10 +177,10 @@ * call this function to retrieve the existing user profile from storage. */ profile: function () { - var profile = $store.get(configuration.profileStorageKey); + var profile = storageService().get(configuration.profileStorageKey); if (_.isObject(profile)) { profile.$apply = function() { - $store.set(configuration.profileStorageKey, _.omit(this, '$apply')); + storageService().set(configuration.profileStorageKey, _.omit(this, '$apply')); }; } return profile; @@ -195,10 +216,10 @@ */ permit: function () { if (this.allowed.apply(this, _.toArray(arguments))) { - $store.remove('attemptedPath'); + storageService().remove('attemptedPath'); return; } - $store.set('attemptedPath', $location.path()); + storageService().set('attemptedPath', $location.path()); if (this.isAuthenticated()) { $location.path(configuration.notPermittedRedirectPath); } else { @@ -210,7 +231,7 @@ * Returns the path that the user attempts to access before being redirected. */ getAttemptedPath: function () { - return $store.get('attemptedPath'); + return storageService().get('attemptedPath'); }, /** diff --git a/package.json b/package.json index ba98bd8..77faac2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ng-authentication-service", - "version": "0.1.2", + "version": "0.2.0", "author": "Justin Saunders (https://github.com/justinsa)", "contributors": [ "Josh Mackey (https://github.com/joshmackey)", diff --git a/tests.js b/tests.js index 278580d..bc59b4e 100644 --- a/tests.js +++ b/tests.js @@ -3,8 +3,9 @@ describe('services', function () { beforeEach( - module('authentication.service', function ($authenticationProvider) { + module('authentication.service', 'local.storage', function ($authenticationProvider) { $authenticationProvider.configure({ + storageService: '$store', onLoginRedirectPath: '/dashboard', onLogoutRedirectPath: '/home', notPermittedRedirectPath: '/notpermitted', @@ -29,7 +30,8 @@ describe('services', function () { 'isInAllRoles', 'isInAnyRoles', 'permit', - 'getConfiguration' + 'getConfiguration', + 'reauth' ]; for (var i in functions) { $authentication[functions[i]].should.be.a.function; // jshint ignore:line @@ -40,7 +42,8 @@ describe('services', function () { it('should have an expected configuration', inject(function ($authentication) { var configuration = $authentication.getConfiguration(); - (configuration.authCookieKey === null).should.be.true; // jshint ignore:line + configuration.storageService.should.match('$store'); + (configuration.authCookieKey === undefined).should.be.true; // jshint ignore:line configuration.profileStorageKey.should.match('user.profile'); configuration.onLoginRedirectPath.should.match('/dashboard'); configuration.onLogoutRedirectPath.should.match('/home');