Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
280 views
in Technique[技术] by (71.8m points)

javascript - Angular Authentication : Avoid multiple resolve for different routes

I'm developing an Angular application. In this, I'm authenticating the user before going to dashboard. To achieve this I have wrote the signIn function as

Sign-In Function

this.signIn = function(credentials) {
        console.info('AccountController[signIn] Called');

        AuthService
            .login(credentials)
            .then(function(authenticatedUser) {
                $scope.globals['currentUser'] = authenticatedUser;

                AuthService.setCurrentUser(authenticatedUser);

                $scope.globals['isAuthenticated'] = true;
                $location.path('/dashboard');                    

            }).catch(function(error) {
                console.warn('AccountController[signIn] :: ', error);
                Flash.Error(error);
                $scope.credentials.password = '';
            });
    };

I also want to restrict the user from accessing the routes, if they are not logged in. To achieve that I came up with this dirty code.

Routes

$stateProvider
        .state('signIn', {
            url: '/signIn',
            templateUrl: 'partials/signIn/signIn.html',
            data: {
                pageTitle: 'SignIn'
            },
            controller: 'AccountController',
            controllerAs: 'ac',
            resolve: {
                auth: ['$q', 'AuthService', function($q, AuthService) {
                    var userInfo = AuthService.isAuthenticated();
                    console.info('SignIn Route[isAuthenticated] :: ', userInfo);
                    if (!userInfo) {
                        return $q.when(userInfo);
                    } else {
                        return $q.reject({
                            isAuthenticated: true
                        });
                    }
                }]
            }
        })
        .state('dashboard', {
            url: '/dashboard',
            templateUrl: 'partials/dashboard.html',
            controller: 'DashboardController',
            access: {
                requiredLogin: true
            },
            resolve: {
                auth: ['$q', 'AuthService', function($q, AuthService) {
                    var authenticated = AuthService.isAuthenticated();
                    console.info('dashboard Route[isAuthenticated] :: ', authenticated);
                    if (authenticated) {
                        return $q.when(authenticated);
                    } else {
                        return $q.reject({
                            isAuthenticated: false
                        });
                    }
                }]
            }
        })
        .state('manageStudent', {
            url: '/manageStudent',
            templateUrl: 'partials/manageStudent.html',
            access: {
                requiredLogin: true
            },
            resolve: {
                auth: ['$q', 'AuthService', function($q, AuthService) {
                    var authenticated = AuthService.isAuthenticated();
                    if (authenticated) {
                        return $q.when(authenticated);
                    } else {
                        return $q.reject({
                            isAuthenticated: false
                        });
                    }
                }]
            }
        });


App.run(['$rootScope', 'settings', '$state', 'AuthService', '$location', function($rootScope, settings, $state, AuthService, $location) {
    $rootScope.$state = $state; // state to be accessed from view
    $rootScope.$settings = settings; // state to be accessed from view

    $rootScope.$on('$stateChangeStart', function(event, next,nextParams,prev,prevParams) {

        // If the user is logged in don't allow him to land on the Login Page


        if (next.access !== undefined) {
            if (next.access.requiredLogin && !AuthService.isAuthenticated()) {

                $location.path('/signIn');
            }
        }


    });


    $rootScope.$on('$stateChangeError', function(event, toState, toParams, fromState, fromParams, error) {

        event.preventDefault();
        if (!error.isAuthenticated) {
            console.warn("I'm not Authenticated.Going to Sign-in");

            return $location.path('/signIn');
        } else {
            console.info("I'm Authenticated");
            $location.path('/dashboard');

        }
    });
}]);

Reason I said the above code DIRTY is because, If I have 10 routes which I want to protect from Unauthenticated user, I have to copy the same resolve function in all the routes.

So my question is , what should I do to get rid of multiple resolve function and being able to write DRY code?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Since auth should be resolved on each route change, it is insufficient to just wrap it into separate factory (which is a singleton and will run only once). To get round this limitation it should be a function

app.factory('authResolver', function ($q, AuthService) {
  return function () {
    // ...
  };
});

which runs on every route resolve

...
resolve: {
  auth: function (authResolver) {
    return authResolver();
  }
}

Still not that DRY, but that's the recommended humidity level.

More radical approach that may save the one from boilerplate resolve and save a few lines of code will be similar to that:

app.run(function ($rootScope, authResolver) {
  $rootScope.$on('$stateChangeStart', function (e, to) {
    if (to.doAuthPlease)
      to.resolve.auth = authResolver();
  });
});

and

...
doAuthPlease: true,
resolve: {}

The obvious difference with ngRoute in the mentioned answer is that in UI Router you need to have resolve object defined to be able to add new resolvers to the state dynamically. It can be treated like that or leaved as is.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...