fnakstad / angular-client-side-auth

One way to implement authentication/authorization in Angular applications
http://angular-client-side-auth.herokuapp.com/
MIT License
1.63k stars 346 forks source link

ui-router - Call for comments and ideas #54

Closed fnakstad closed 10 years ago

fnakstad commented 10 years ago

I'm in the middle of migrating from ngroute to ui-router, and am trying to figure out the best way to handle things when it comes to nested views and other ui-router features. Since a lot of people following this repo have requested this feature and are using ui-router in various projects, I'm hoping you all can help me with some comments and ideas on how you want this to work. Clone the new branch, ui-router-migration, to test it out. This is how my proposed solution works as of now:

The access property must now be set as a child of the data property. An excellent side-effect of this is that child views inherit access properties from their parents while still offering to set them explicitly. This means you can now organise your application into “areas” which define the access restrictions for all nested views by making said states abstract and adding a basic template where you just insert a ui-view tag. Here’s an example of how it looks like:

// Regular user routes
$stateProvider
    .state('user', {
        abstract: true,
        template: "<ui-view/>",
        data: {
            access: access.user
        }
    })
    .state('user.home', {
        url: '/',
        templateUrl: 'home'
    })
    .state('user.private', {
        abstract: true,
        url: '/private/',
        templateUrl: 'private/layout'
    })
    .state('user.private.home', {
        url: '',
        templateUrl: 'private/home'
    })
    .state('user.private.nested', {
        url: 'nested/',
        templateUrl: 'private/nested'
    })
    .state('user.private.admin', {
        url: 'admin/',
        templateUrl: 'private/nestedAdmin',
        data: {
            access: access.admin
        }
    }); 

Another change is in the $stateChangeStart handler which has been updated to handle unauthorized accesses in a slightly different manner:


$rootScope.$on("$stateChangeStart", function (event, toState, toParams, fromState, fromParams) {
    if (!Auth.authorize(toState.data.access)) {
        event.preventDefault();
        if(fromState.url === '^') {
            if(Auth.isLoggedIn())    $state.go('user.home');
            else                     $state.go('anon.login');
        }
        $rootScope.error = "Seems like you tried accessing a route you don't have access to...";
    }
}); 

Instead of simply redirecting you, it now prevents the state change and pops up an error message. If the navigation is the result of a full page reload however, it will additionally redirect you to an appropriate state depending on login status.

Please give me input on what you think about this approach, and come with any other suggestions about things that should be included before merging this into master. Many of you have worked with UI-Router much longer than I, so I’d be very interested to hear more about the different ways it is used :)

elliottregan commented 10 years ago

I used a similar method in an Angular app, although I never connected it to a backend.

The idea was that the patent state controller would handle the authorization, and a nested ui-view would load the next child based on the route and initialize the data. Child states could only be loaded if their parent was authorized, so you didn't have to double check on each page load.

fnakstad commented 10 years ago

Cool! Good to know we approached this similarly :) I'll merge this branch into master hopefully within this week.

fnakstad commented 10 years ago

This has now been merged into master.