javascript - AngularJS Authentication + RESTful API -
angular+restful client-side communication w/ api auth/(re)routing
this has been covered in few different questions, , in few different tutorials, of previous resources i've encountered don't quite hit nail on head.
in nut-shell, need to
- login via post
http://client.foo
http://api.foo/login
- have "logged in" gui/component state user provides
logout
route - be able "update" ui when user logs out / logs out. this has been frustrating
- secure routes check authenticated-state (should need it) , redirect user login page accordingly
my issues are
- every time navigate different page, need make call
api.foo/status
determine whether or not user logged in. (atm i'm using express routes) causes hiccup angular determines thingsng-show="user.is_authenticated"
- when login/logout, need refresh page (i don't want have this) in order populate things
{{user.first_name}}
, or in case of logging out, empty value out.
// sample response `/status` if successful { customer: {...}, is_authenticated: true, authentication_timeout: 1376959033, ... }
what i've tried
- http://witoldsz.github.io/angular-http-auth/1
- http://www.frederiknakstad.com/authentication-in-single-page-applications-with-angular-js/2
- https://github.com/mgonto/restangular (for life of me not figure out how
post
post data
, notquery params
. docs turned nothing on matter.
why feel i'm losing mind
- it seems though every tutorial relies on database (lots of mongo, couch, php+mysql, ad infinitum) solution, , none rely purely on communication restful api persist logged-in states. once logged in, additional posts/gets sent
withcredentials:true
, that's not issue - i cannot find examples/tutorials/repos angular+rest+auth, sans backend language.
i'm not proud
admittedly, i'm new angular, , not surprised if i'm approaching in ridiculous way; i'd thrilled if suggest alternative—even if it's soup-to-nuts.
i'm using express
because love jade
, stylus
— i'm not married express
' routing , give if want possible angular's routing.
thanks in advance can provide. , please don't ask me google it, because have 26 pages of purple links. ;-)
1this solution relies on angular's $httpbackend mock, , it's unclear how make talk real server.
2this closest, since have existing api need authenticate with, not use passport's 'localstrategy', , seemed insane write oauth service...that intended use.
this taken blog post on url route authorisation , element security here briefly summaries main points :-)
security in frontend web application merely starting measure stop joe public, user web knowledge can circumvent should have security server-side well.
the main concern around security stuff in angular route security, luckily when defining route in angular create object, object can have other properties. cornerstone approach add security object route object defines roles user must in able access particular route.
// route requires user logged in , have 'admin' or 'usermanager' permission $routeprovider.when('/admin/users', { controller: 'userlistctrl', templateurl: 'js/modules/admin/html/users.tmpl.html', access: { requireslogin: true, requiredpermissions: ['admin', 'usermanager'], permissiontype: 'atleastone' });
the whole approach focuses around authorisation service check see if user has required permissions. service abstract concerns away other parts of solution user , actual permission have been retrieved server during login. while code quite verbose explained in blog post. however, handle permission check , 2 modes of authorisation. first user must have @ least on of defined permissions, second user must have of defined permissions.
angular.module(jcs.modules.auth.name).factory(jcs.modules.auth.services.authorization, [ 'authentication', function (authentication) { var authorize = function (loginrequired, requiredpermissions, permissionchecktype) { var result = jcs.modules.auth.enums.authorised.authorised, user = authentication.getcurrentloginuser(), loweredpermissions = [], haspermission = true, permission, i; permissionchecktype = permissionchecktype || jcs.modules.auth.enums.permissionchecktype.atleastone; if (loginrequired === true && user === undefined) { result = jcs.modules.auth.enums.authorised.loginrequired; } else if ((loginrequired === true && user !== undefined) && (requiredpermissions === undefined || requiredpermissions.length === 0)) { // login required no specific permissions specified. result = jcs.modules.auth.enums.authorised.authorised; } else if (requiredpermissions) { loweredpermissions = []; angular.foreach(user.permissions, function (permission) { loweredpermissions.push(permission.tolowercase()); }); (i = 0; < requiredpermissions.length; += 1) { permission = requiredpermissions[i].tolowercase(); if (permissionchecktype === jcs.modules.auth.enums.permissionchecktype.combinationrequired) { haspermission = haspermission && loweredpermissions.indexof(permission) > -1; // if permissions required , haspermission false there no point carrying on if (haspermission === false) { break; } } else if (permissionchecktype === jcs.modules.auth.enums.permissionchecktype.atleastone) { haspermission = loweredpermissions.indexof(permission) > -1; // if need 1 of permissions , have there no point carrying on if (haspermission) { break; } } } result = haspermission ? jcs.modules.auth.enums.authorised.authorised : jcs.modules.auth.enums.authorised.notauthorised; } return result; };
now route has security need way of determining if user can access route when route change has been started. intercepting route change request, examining route object (with our new access object on it) , if user cannot access view replace route one.
angular.module(jcs.modules.auth.name).run([ '$rootscope', '$location', jcs.modules.auth.services.authorization, function ($rootscope, $location, authorization) { $rootscope.$on('$routechangestart', function (event, next) { var authorised; if (next.access !== undefined) { authorised = authorization.authorize(next.access.loginrequired, next.access.permissions, next.access.permissionchecktype); if (authorised === jcs.modules.auth.enums.authorised.loginrequired) { $location.path(jcs.modules.auth.routes.login); } else if (authorised === jcs.modules.auth.enums.authorised.notauthorised) { $location.path(jcs.modules.auth.routes.notauthorised).replace(); } } }); }]);
the key here '.replace()' replace current route (the 1 have not got rights see) route redirecting them to. stop navigating unauthorised route.
now can intercept routes can quite few cool things including redirecting after login if user landed on route needed logged in for.
the second part of solution being able hide/show ui element user depending on there rights. achieve via simple directive.
angular.module(jcs.modules.auth.name).directive('access', [ jcs.modules.auth.services.authorization, function (authorization) { return { restrict: 'a', link: function (scope, element, attrs) { var makevisible = function () { element.removeclass('hidden'); }, makehidden = function () { element.addclass('hidden'); }, determinevisibility = function (resetfirst) { var result; if (resetfirst) { makevisible(); } result = authorization.authorize(true, roles, attrs.accesspermissiontype); if (result === jcs.modules.auth.enums.authorised.authorised) { makevisible(); } else { makehidden(); } }, roles = attrs.access.split(','); if (roles.length > 0) { determinevisibility(true); } } }; }]);
you sure element so:
<button type="button" access="canedituser, admin" access-permission-type="atleastone">save user</button>
read full blog post more detailed overview approach.
Comments
Post a Comment