簡體   English   中英

使用有角度的前端處理身份驗證->如何保護特定頁面?

[英]Handling authentication with angular front-end -> How to protect specific pages?

希望在Node.js中構建具有用戶登錄(身份驗證)功能的Web應用程序,該應用程序具有3個非安全頁面(/ home,/ contact,/ about)和一個安全頁面(/ admin)。 順便說一句,我一直在參考scotch.io Mean Machine書。

我遇到的問題是我已經將所有內容都構建好了,登錄機制的工作原理是:登錄時,我被定向到/ admin; 但是,當我不登錄而進入URL中的/ admin時,仍可以訪問該頁面。 也就是說,我不確定將實際保護放在何處。

下面是我如何布置應用程序的信息。 希望有一個概念上的答案來建議我應該如何做,而不是僅是代碼答案。

服務:

  • auth服務將輸入的用戶名/密碼發布到服務器,並返回false或成功(帶有用戶信息和JWT令牌)
  • auth服務還將令牌(如果有)作為AuthInterceptor注入到每個HTTP標頭中

路由器:

angular.module('routerRoutes', ['ngRoute'])
    .config(function($routeProvider, $locationProvider) {
        $routeProvider
            .when('/', {
                templateUrl:    'views/home.html',
                controller:     'homeController',
                controllerAs:   'home'
            })
            .when('/about', {
                templateUrl:    'views/about.html',
                controller:     'aboutController',
                controllerAs:   'about'
            })
            .when('/contact', {
                templateUrl:    'views/contact.html',
                controller:     'contactController',
                controllerAs:   'contact'
            })
            .when('/login', {
                templateUrl:    'views/login.html',
                controller:     'adminController',
                controllerAs:   'login'
            })
            .when('/admin', {
                templateUrl:    'views/admin/admin.html',
                controller:     'adminController',
                controllerAs:   'admin'
            });

        $locationProvider.html5Mode(true);

    });

控制器:

  • homeController,aboutController和contactController通常現在為空

  • adminController:

    .controller('adminController',function($ rootScope,$ location,Auth){

     var vm = this; vm.loggedIn = Auth.isLoggedIn(); $rootScope.$on('$routeChangeStart', function() { vm.loggedIn = Auth.isLoggedIn(); window.alert(vm.loggedIn); // this gives correct answer and works Auth.getUser() .success(function(data) { vm.user = data; }); }); vm.doLogin = function() { vm.error = ''; Auth.login(vm.loginData.username, vm.loginData.password) .success(function(data) { vm.user = data.username; if (data.success) $location.path('/admin'); else vm.error = data.message; }); }; vm.doLogout = function() { Auth.logout(); vm.user = {}; $location.path('/login'); }; 

    });

最后,下面是我的index.html(僅是正文):

<body class="container" ng-app="meanApp" ng-controller="adminController as admin">

    <a href="/"><i class="fa fa-home">Home </i></a>
    <a href="/about"><i class="fa fa-shield">About </i></a>
    <a href="/contact"><i class="fa fa-comment">Contact</i></a>
    <a href="/admin"><i class="fa fa-comment">Admin</i></a>

    <ul class="nav navbar-nav navbar-right">
        <li ng-if="!admin.loggedIn"><a href="/login">Login</a></li>
        <li ng-if="admin.loggedIn" class="navbar-text">Hello {{ admin.user.username }}</li>
        <li ng-if="admin.loggedIn"><a href="#" ng-click="admin.doLogout()">Logout</a></li>
    </ul>

    <main>
        <div ng-view>

        </div>
    </main>

</body>

我將不會粘貼注入的其他html頁面,因為它們上還沒有任何東西(login.html只有兩個輸入字段和提交按鈕)。

有幾個問題:

  • 在我的index.html中,當我單擊/ admin時,即使我沒有登錄,它也帶我進入管理頁面。我應該在哪里防止這種情況發生?
  • 對我未遵循的設置和最佳做法有任何一般性評論嗎?

另一個優點:

  • 我讀到,如果未命中決策樹的該分支,則不會在“查看源代碼”中顯示“ li ng-if =“,但確實如此。 我被誤導了還是做錯了什么?

我采用了自定義屬性路由來保護應用程序中的路由。 偵聽並檢查每個發生的狀態更改是否具有此屬性。 如果設置了此屬性,則它將檢查用戶是否已登錄;如果未登錄,則會將其路由到“登錄”狀態。

我在實現該功能的當前項目中使用了UI-ROUTER。 我在路由中使用了一個自定義參數“ data”。

在.config塊中聲明我的開放路線:

      $stateProvider
         .state('login', {
             url: '/login',
             templateUrl: 'login/login.html',
             controller: 'LoginController',
             controllerAs: 'vm'
          })
         .state('home', {
             url: '',
             templateUrl: 'layout/shell.html',
             controller: 'ShellController',
             controllerAs: 'vm',
             data: {
                 requireLogin: true
             }
          })

然后,將其添加到應用程序中的.run,在其中查找ui路由器的$ stateChangeStart事件並在狀態聲明中查看我的自定義屬性(“數據”):

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

        var requireLogin = toState.hasOwnProperty('data') && toState.data.requireLogin;
        if (requireLogin && !authService.isLoggedIn()) {
            event.preventDefault();
            authService.setDestinationState(toState.name);
            $state.go('login');
        }

        if (toState.name !== 'login') {
            authService.setDestinationState(toState.name);
        }
    });

如果您想知道authService.setDestinationState的功能是什么...它將保留用戶嘗試訪問的URL ...一旦成功登錄,它將自動將其轉發到該狀態(請參見下文):

     function login() {
        authService.authLogin(vm.credentials)
            .then(loginComplete)
            .catch(loginFailed);

        function loginComplete(data, status, headers, config) {
            vm.user = data;
            $rootScope.$broadcast('authorized');
            $state.go(authService.getDestinationState());
        }

        function loginFailed(status) {
            console.log('XHR Failed for login.');
            vm.user = undefined;
            vm.error = 'Error: Invalid user or password. ' + status.error;
            toastr.error(vm.error, {closeButton: true} );
        }
    }

定義管理路由時,可以定義一個名為resolve的屬性。 resolve中的每個屬性都是一個函數(可以是可注入函數)。 這個函數應該返回一個promise,promise的結果可以注入到控制器中。

有關解決的更多信息,請參見http://odetocode.com/blogs/scott/archive/2014/05/20/using-resolve-in-angularjs-routes.aspx

您可以按以下方式使用resolve進行身份驗證檢查。

var authenticateRoute = ['$q', '$http' , function ($q, $http) {
    var deferred = $q.defer();
    $http.get("http://api.domain.com/whoami")
         .then(function(response) { 
                   if (response.data.userId) deferred.resolve(response.data.userId);  
                   else window.location.href = "#/Login"
               });
    return deferred.promise();
}]

// ...

.when('/admin', {
    templateUrl:    'views/admin/admin.html',
    controller:     'adminController',
    controllerAs:   'admin',
    resolve: {
        authenticatedAs: authenticateRoute
    }
});

這樣,您可以傳遞經過身份驗證的用戶ID(即使為null),也可以讓控制器處理它,例如,如果您需要上下文消息。 否則,您可以執行上述操作,並且僅在身份驗證請求中有用戶ID時才這樣做,否則重定向到您的登錄路由。

希望這可以幫助! / AJ

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM