首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >AngularJS-在每个路由和控制器中进行登录和身份验证

AngularJS-在每个路由和控制器中进行登录和身份验证
EN

Stack Overflow用户
提问于 2014-01-07 18:56:38
回答 10查看 220.7K关注 0票数 132

我有一个用yeoman,grunt和bower创建的AngularJS应用程序。

我有一个登录页面,它有一个检查身份验证的控制器。如果凭据是正确的,我会重新路由到主页。

app.js

代码语言:javascript
复制
'use strict';
//Define Routing for app
angular.module('myApp', []).config(['$routeProvider', '$locationProvider',
  function($routeProvider,$locationProvider) {
    $routeProvider
    .when('/login', {
        templateUrl: 'login.html',
        controller: 'LoginController'
    })
    .when('/register', {
        templateUrl: 'register.html',
        controller: 'RegisterController'
      })
    .when('/forgotPassword', {
        templateUrl: 'forgotpassword.html',
        controller: 'forgotController'
      })
   .when('/home', {
       templateUrl: 'views/home.html',
       controller: 'homeController'
    })
    .otherwise({
       redirectTo: '/login'
    });
//    $locationProvider.html5Mode(true); //Remove the '#' from URL.
}]);

angular.module('myApp').factory("page", function($rootScope){
    var page={};
    var user={};
    page.setPage=function(title,bodyClass){
        $rootScope.pageTitle = title;
        $rootScope.bodylayout=bodyClass;
    };
    page.setUser=function(user){
        $rootScope.user=user;
    }
    return page;
});

LoginControler.js

代码语言:javascript
复制
'use strict';

angular.module('myApp').controller('LoginController', function($scope, $location, $window,page) {
    page.setPage("Login","login-layout");
    $scope.user = {};
    $scope.loginUser=function()
    {
        var username=$scope.user.name;
        var password=$scope.user.password;
        if(username=="admin" && password=="admin123")
        {
            page.setUser($scope.user);
            $location.path( "/home" );
        }
        else
        {
            $scope.message="Error";
            $scope.messagecolor="alert alert-danger";
        }
    }
});

在我的主页上

代码语言:javascript
复制
<span class="user-info">
    <small>Welcome,</small>
    {{user.name}}
</span>
<span class="logout"><a href="" ng-click="logoutUser()">Logout</a></span>

loginController中,我检查登录信息,如果成功,就在服务工厂中设置user对象。我不知道这是对是错。

我需要的是,当用户登录时,它在user对象中设置一些值,以便所有其他页面都可以获得该值。

每当发生任何路由更改时,控制器都应该检查用户是否登录。如果不是,它应该重新路由到登录页面。此外,如果用户已经登录并返回到页面,它应该转到主页。控制器还应该检查所有路由上的凭证。

我听说过ng-cookie,但我不知道如何使用它们。

我看到的许多示例都不是很清楚,它们使用了某种访问角色或其他什么。我不想这样。我只想要一个登录过滤器。有没有人能给我一些建议?

EN

回答 10

Stack Overflow用户

回答已采纳

发布于 2014-01-07 20:22:56

我的解决方案分为三个部分:用户的状态存储在服务中,在run方法中,当路由发生变化时,您可以查看用户是否被允许访问请求的页面,在主控制器中,您可以查看用户的状态是否发生了变化。

代码语言:javascript
复制
app.run(['$rootScope', '$location', 'Auth', function ($rootScope, $location, Auth) {
    $rootScope.$on('$routeChangeStart', function (event) {

        if (!Auth.isLoggedIn()) {
            console.log('DENY');
            event.preventDefault();
            $location.path('/login');
        }
        else {
            console.log('ALLOW');
            $location.path('/home');
        }
    });
}]);

您应该创建一个服务(我将其命名为Auth),该服务将处理user对象,并具有一个方法来了解用户是否已登录。

服务

代码语言:javascript
复制
 .factory('Auth', function(){
var user;

return{
    setUser : function(aUser){
        user = aUser;
    },
    isLoggedIn : function(){
        return(user)? user : false;
    }
  }
})

在您的app.run中,您应该监听$routeChangeStart事件。当路由更改时,它将检查用户是否已登录( isLoggedIn方法应处理此问题)。如果用户没有登录,它不会加载请求的路由,它会将用户重定向到正确的页面(在您的情况下是登录)。

应该在登录页面中使用loginController来处理登录。它应该只是与Auth服务交互,并将用户设置为已登录或未登录。

loginController

代码语言:javascript
复制
.controller('loginCtrl', [ '$scope', 'Auth', function ($scope, Auth) {
  //submit
  $scope.login = function () {
    // Ask to the server, do your job and THEN set the user

    Auth.setUser(user); //Update the state of the user in the app
  };
}])

在主控制器中,您可以监听用户状态是否发生更改,并通过重定向做出反应。

代码语言:javascript
复制
.controller('mainCtrl', ['$scope', 'Auth', '$location', function ($scope, Auth, $location) {

  $scope.$watch(Auth.isLoggedIn, function (value, oldValue) {

    if(!value && oldValue) {
      console.log("Disconnect");
      $location.path('/login');
    }

    if(value) {
      console.log("Connect");
      //Do something when the user is connected
    }

  }, true);
票数 182
EN

Stack Overflow用户

发布于 2015-04-22 20:09:47

这是另一种可能的解决方案,使用$stateProvider$routeProviderresolve属性。使用$stateProvider的示例

代码语言:javascript
复制
.config(["$stateProvider", function ($stateProvider) {

  $stateProvider

  .state("forbidden", {
    /* ... */
  })

  .state("signIn", {
    /* ... */
    resolve: {
      access: ["Access", function (Access) { return Access.isAnonymous(); }],
    }
  })

  .state("home", {
    /* ... */
    resolve: {
      access: ["Access", function (Access) { return Access.isAuthenticated(); }],
    }
  })

  .state("admin", {
    /* ... */
    resolve: {
      access: ["Access", function (Access) { return Access.hasRole("ROLE_ADMIN"); }],
    }
  });

}])

Access根据当前用户权限解决或拒绝承诺:

代码语言:javascript
复制
.factory("Access", ["$q", "UserProfile", function ($q, UserProfile) {

  var Access = {

    OK: 200,

    // "we don't know who you are, so we can't say if you're authorized to access
    // this resource or not yet, please sign in first"
    UNAUTHORIZED: 401,

    // "we know who you are, and your profile does not allow you to access this resource"
    FORBIDDEN: 403,

    hasRole: function (role) {
      return UserProfile.then(function (userProfile) {
        if (userProfile.$hasRole(role)) {
          return Access.OK;
        } else if (userProfile.$isAnonymous()) {
          return $q.reject(Access.UNAUTHORIZED);
        } else {
          return $q.reject(Access.FORBIDDEN);
        }
      });
    },

    hasAnyRole: function (roles) {
      return UserProfile.then(function (userProfile) {
        if (userProfile.$hasAnyRole(roles)) {
          return Access.OK;
        } else if (userProfile.$isAnonymous()) {
          return $q.reject(Access.UNAUTHORIZED);
        } else {
          return $q.reject(Access.FORBIDDEN);
        }
      });
    },

    isAnonymous: function () {
      return UserProfile.then(function (userProfile) {
        if (userProfile.$isAnonymous()) {
          return Access.OK;
        } else {
          return $q.reject(Access.FORBIDDEN);
        }
      });
    },

    isAuthenticated: function () {
      return UserProfile.then(function (userProfile) {
        if (userProfile.$isAuthenticated()) {
          return Access.OK;
        } else {
          return $q.reject(Access.UNAUTHORIZED);
        }
      });
    }

  };

  return Access;

}])

UserProfile复制当前的用户属性,并实现$hasRole$hasAnyRole$isAnonymous$isAuthenticated方法逻辑(以及稍后解释的$refresh方法):

代码语言:javascript
复制
.factory("UserProfile", ["Auth", function (Auth) {

  var userProfile = {};

  var clearUserProfile = function () {
    for (var prop in userProfile) {
      if (userProfile.hasOwnProperty(prop)) {
        delete userProfile[prop];
      }
    }
  };

  var fetchUserProfile = function () {
    return Auth.getProfile().then(function (response) {
      clearUserProfile();
      return angular.extend(userProfile, response.data, {

        $refresh: fetchUserProfile,

        $hasRole: function (role) {
          return userProfile.roles.indexOf(role) >= 0;
        },

        $hasAnyRole: function (roles) {
          return !!userProfile.roles.filter(function (role) {
            return roles.indexOf(role) >= 0;
          }).length;
        },

        $isAnonymous: function () {
          return userProfile.anonymous;
        },

        $isAuthenticated: function () {
          return !userProfile.anonymous;
        }

      });
    });
  };

  return fetchUserProfile();

}])

Auth负责请求服务器,以了解用户配置文件(例如,链接到附加到请求的访问令牌):

代码语言:javascript
复制
.service("Auth", ["$http", function ($http) {

  this.getProfile = function () {
    return $http.get("api/auth");
  };

}])

服务器需要在请求GET api/auth时返回这样的JSON对象。

代码语言:javascript
复制
{
  "name": "John Doe", // plus any other user information
  "roles": ["ROLE_ADMIN", "ROLE_USER"], // or any other role (or no role at all, i.e. an empty array)
  "anonymous": false // or true
}

最后,如果使用ui.router,当Access拒绝一个promise时,将触发$stateChangeError事件:

代码语言:javascript
复制
.run(["$rootScope", "Access", "$state", "$log", function ($rootScope, Access, $state, $log) {

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

    case Access.UNAUTHORIZED:
      $state.go("signIn");
      break;

    case Access.FORBIDDEN:
      $state.go("forbidden");
      break;

    default:
      $log.warn("$stateChangeError event catched");
      break;

    }
  });

}])

如果使用ngRoute,将触发$routeChangeError事件:

代码语言:javascript
复制
.run(["$rootScope", "Access", "$location", "$log", function ($rootScope, Access, $location, $log) {

  $rootScope.$on("$routeChangeError", function (event, current, previous, rejection) {
    switch (rejection) {

    case Access.UNAUTHORIZED:
      $location.path("/signin");
      break;

    case Access.FORBIDDEN:
      $location.path("/forbidden");
      break;

    default:
      $log.warn("$stateChangeError event catched");
      break;

    }
  });

}])

还可以在控制器中访问用户配置文件:

代码语言:javascript
复制
.state("home", {
  /* ... */
  controller: "HomeController",
  resolve: {
    userProfile: "UserProfile"
  }
})

然后,UserProfile包含服务器在请求GET api/auth时返回的属性

代码语言:javascript
复制
.controller("HomeController", ["$scope", "userProfile", function ($scope, userProfile) {

  $scope.title = "Hello " + userProfile.name; // "Hello John Doe" in the example

}])

当用户登录或注销时,需要刷新UserProfile,以便Access可以使用新的用户配置文件处理路由。您可以重新加载整个页面,也可以调用UserProfile.$refresh()。登录时的示例:

代码语言:javascript
复制
.service("Auth", ["$http", function ($http) {

  /* ... */

  this.signIn = function (credentials) {
    return $http.post("api/auth", credentials).then(function (response) {
      // authentication succeeded, store the response access token somewhere (if any)
    });
  };

}])
代码语言:javascript
复制
.state("signIn", {
  /* ... */
  controller: "SignInController",
  resolve: {
    /* ... */
    userProfile: "UserProfile"
  }
})
代码语言:javascript
复制
.controller("SignInController", ["$scope", "$state", "Auth", "userProfile", function ($scope, $state, Auth, userProfile) {

  $scope.signIn = function () {
    Auth.signIn($scope.credentials).then(function () {
      // user successfully authenticated, refresh UserProfile
      return userProfile.$refresh();
    }).then(function () {
      // UserProfile is refreshed, redirect user somewhere
      $state.go("home");
    });
  };

}])
票数 113
EN

Stack Overflow用户

发布于 2016-07-11 09:23:42

定义单个路由的自定义行为的最直接方式将非常简单:

1)为routes.js**:创建一个新属性(如** requireAuth**) **

代码语言:javascript
复制
angular.module('yourApp').config(function($routeProvider) {
    $routeProvider
        .when('/home', {
            templateUrl: 'templates/home.html',
            requireAuth: true // our custom property
        })
        .when('/login', {
            templateUrl: 'templates/login.html',
        })
        .otherwise({
            redirectTo: '/home'
        });
})

代码2)在未绑定到angular ng-view $routeProvider内部元素的顶级控制器中(为避免与ng-view$routeProvider冲突),检查是否具有属性并采取相应操作<>E230

代码语言:javascript
复制
 angular.module('YourApp').controller('YourController', function ($scope, $location, session) {
     
     // intercept the route change event
     $scope.$on('$routeChangeStart', function (angularEvent, newUrl) {
         
         // check if the custom property exist
         if (newUrl.requireAuth && !session.user) {
             
             // user isn’t authenticated
             $location.path("/login");
         }
     });
 });
票数 21
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/20969835

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档