AngularJS-每个路由和控制器中的login和authentication

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

我有一个login页面,有一个控制器来检查身份validation。 如果凭证是正确的我重新路由到主页。

app.js

'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

 '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"; } } }); 

在我的主页上

 <span class="user-info"> <small>Welcome,</small> {{user.name}} </span> <span class="logout"><a href="" ng-click="logoutUser()">Logout</a></span> 

loginController ,我检查login信息,如果成功,我在服务工厂中设置用户对象。 我不知道这是否正确。

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

无论何时发生路由变化,控制器都应该检查用户是否login。 如果没有,应该重新路由到login页面。 另外,如果用户已经login并返回页面,则应该进入主页。 控制器还应该检查所有路线上的凭证。

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

我看到的很多例子都不是很清楚,他们使用某种访问angular色或者某种东西。 我不要那个。 我只想要一个loginfilter。 有人能给我一些想法吗?

我的解决scheme分为三个部分:用户的状态存储在服务中,在path更改时您观察的运行方法中,并检查用户是否被允许访问请求的页面,在您观察的主控制器中用户的状态改变。

 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'); } }); }]); 

你应该创build一个服务(我将其命名为Auth ),它将处理用户对象,并有一个方法来知道用户是否login。

服务

  .factory('Auth', function(){ var user; return{ setUser : function(aUser){ user = aUser; }, isLoggedIn : function(){ return(user)? user : false; } } }) 

从你的app.run ,你应该听$routeChangeStart事件。 当路由改变时,它将检查用户是否被logging( isLoggedIn方法应该处理它)。 如果用户没有login,它将不会加载请求的路由,它将把用户redirect到正确的页面(在你的情况下login)。

login页面应该使用loginController来处理login。 它应该只是与Auth服务进行Auth ,并将用户设置为已login或未login。

loginController

 .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 }; }]) 

从你的主控制器,你可以听取用户状态是否改变,并作出redirect的反应。

 .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); 

这是另一个可能的解决scheme,使用$stateProviderresolve属性或$routeProvider$stateProvider

 .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根据当前用户权限parsing或拒绝承诺:

 .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方法,稍后解释):

 .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负责请求服务器,了解用户configuration文件(链接到附加到请求的访问令牌):

 .service("Auth", ["$http", function ($http) { this.getProfile = function () { return $http.get("api/auth"); }; }]) 

请求GET api/auth时,服务器应该返回这样的JSON对象:

 { "name": "John Doe", // plus any other user information "roles": ["ROLE_ADMIN", "ROLE_USER"], // or any other role (or no role at all, ie an empty array) "anonymous": false // or true } 

最后,当Access拒绝承诺时,如果使用ui.router$stateChangeError事件将被触发:

 .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事件将被触发:

 .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; } }); }]) 

用户configuration文件也可以在控制器中访问:

 .state("home", { /* ... */ controller: "HomeController", resolve: { userProfile: "UserProfile" } }) 

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

 .controller("HomeController", ["$scope", "userProfile", function ($scope, userProfile) { $scope.title = "Hello " + userProfile.name; // "Hello John Doe" in the example }]) 

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

 .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) }); }; }]) 
 .state("signIn", { /* ... */ controller: "SignInController", resolve: { /* ... */ userProfile: "UserProfile" } }) 
 .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"); }); }; }]) 

为单个路线定义自定义行为最简单的方法将是相当简单的:

1) routes.js :创build一个新的属性(如requireAuth )任何所需的路线

 angular.module('yourApp').config(['$routeProvider', function($routeProvider) { $routeProvider .when('/home', { templateUrl: 'templates/home.html', requireAuth: true }) .when('/login', { templateUrl: 'templates/login.html', }) .otherwise({ redirectTo: '/home' }); }]) 

2)在没有绑定到ng-view的元素的顶层控制器(为了避免与$routeProviderangular度冲突),检查newUrl是否具有requireAuth属性并相应地执行

 angular.module('YourApp').controller('YourController', ['$scope', 'session', '$location', function($scope, session, $location) { $scope.$on('$routeChangeStart', function(angularEvent, newUrl) { if (newUrl.requireAuth && !session.user) { // User isn't authenticated $location.path("/login"); } }); } ]); 

几个月前,我就写了一篇关于如何设置Angular的用户注册和loginfunction的文章,你可以在http://jasonwatmore.com/post/2015/03/10/AngularJS-User-Registration- -Login-Example.aspx

我检查用户是否login$locationChangeStart事件,这里是我的主要app.js显示:

 (function () {    'use strict';    angular        .module('app', ['ngRoute', 'ngCookies'])        .config(config)        .run(run);    config.$inject = ['$routeProvider', '$locationProvider'];    function config($routeProvider, $locationProvider) {        $routeProvider            .when('/', {                controller: 'HomeController',                templateUrl: 'home/home.view.html',                controllerAs: 'vm'            })            .when('/login', {                controller: 'LoginController',                templateUrl: 'login/login.view.html',                controllerAs: 'vm'            })            .when('/register', {                controller: 'RegisterController',                templateUrl: 'register/register.view.html',                controllerAs: 'vm'            })            .otherwise({ redirectTo: '/login' });    }    run.$inject = ['$rootScope', '$location', '$cookieStore', '$http'];    function run($rootScope, $location, $cookieStore, $http) {        // keep user logged in after page refresh        $rootScope.globals = $cookieStore.get('globals') || {};        if ($rootScope.globals.currentUser) {            $http.defaults.headers.common['Authorization'] = 'Basic ' + $rootScope.globals.currentUser.authdata; // jshint ignore:line        }        $rootScope.$on('$locationChangeStart', function (event, next, current) {            // redirect to login page if not logged in and trying to access a restricted page            var restrictedPage = $.inArray($location.path(), ['/login', '/register']) === -1;            var loggedIn = $rootScope.globals.currentUser;            if (restrictedPage && !loggedIn) {                $location.path('/login');            }        });    } })(); 

我觉得这种方式最简单,但也许只是个人喜好。

当您指定您的login路线(和其他任何匿名路线;例如:/ register,/ logout,/ refreshToken等)时,请添加:

 allowAnonymous: true 

所以,这样的事情:

 $stateProvider.state('login', { url: '/login', allowAnonymous: true, //if you move this, don't forget to update //variable path in the force-page check. views: { root: { templateUrl: "app/auth/login/login.html", controller: 'LoginCtrl' } } //Any other config } 

您不需要指定“allowAnonymous:false”,如果不存在,则在检查中假定为false。 在大多数url被强制authentication的应用程序中,这是不太方便的。 更安全 如果您忘记将其添加到新的URL中,则可能发生的最糟糕的情况是匿名URL受到保护。 如果你这样做,指定“requireAuthentication:true”,你忘了把它添加到一个URL,你正在泄漏一个敏感的页面给公众。

然后在你认为最适合你的代码devise的地方运行这个。

 //I put it right after the main app module config. Ie This thing: angular.module('app', [ /* your dependencies*/ ]) .config(function (/* you injections */) { /* your config */ }) //Make sure there's no ';' ending the previous line. We're chaining. (or just use a variable) // //Then force the logon page .run(function ($rootScope, $state, $location, User /* My custom session obj */) { $rootScope.$on('$stateChangeStart', function(event, newState) { if (!User.authenticated && newState.allowAnonymous != true) { //Don't use: $state.go('login'); //Apparently you can't set the $state while in a $state event. //It doesn't work properly. So we use the other way. $location.path("/login"); } }); }); 

例如,一个应用程序有两个用户叫ap和auc。 我传递一个额外的属性到每个路由,并根据我在$ routeChangeStart中获得的数据处理路由。

尝试这个:

 angular.module("app").config(['$routeProvider', function ($routeProvider) { $routeProvider. when('/ap', { templateUrl: 'template1.html', controller: 'template1', isAp: 'ap', }). when('/auc', { templateUrl: 'template2.html', controller: 'template2', isAp: 'common', }). when('/ic', { templateUrl: 'template3.html', controller: 'template3', isAp: 'auc', }). when('/mup', { templateUrl: 'template4.html', controller: 'template4', isAp: 'ap', }). when('/mnu', { templateUrl: 'template5.html', controller: 'template5', isAp: 'common', }). otherwise({ redirectTo: '/ap', }); }]); 

app.js:

 .run(['$rootScope', '$location', function ($rootScope, $location) { $rootScope.$on("$routeChangeStart", function (event, next, current) { if (next.$$route.isAp != 'common') { if ($rootScope.userTypeGlobal == 1) { if (next.$$route.isAp != 'ap') { $location.path("/ap"); } } else { if (next.$$route.isAp != 'auc') { $location.path("/auc"); } } } }); }]); 

所有人都build议大的解决scheme,为什么你担心客户端的会话。 我的意思是当状态/url的变化,我想你正在做一个Ajax调用来加载温度的数据。

 Note :- To Save user's data you may use `resolve` feature of `ui-router`. Check cookie if it exist load template , if even cookies doesn't exist than there is no chance of logged in , simply redirect to login template/page. 

现在ajax数据由服务器使用任何api返回。 现在这一点起作用了,根据用户的login状态返回使用服务器的标准返回types。 检查这些返回代码并在控制器中处理您的请求。 注意: – 对于本地不需要ajax调用的控制器,可以调用一个空的请求到server.location/api/checkSession.php ,这是checkSession.php

 <?php/ANY_LANGUAGE session_start();//You may use your language specific function if required if(isset($_SESSION["logged_in"])){ set_header("200 OK");//this is not right syntax , it is just to hint } else{ set_header("-1 NOT LOGGED_IN");//you may set any code but compare that same //code on client side to check if user is logged in or not. } //thanks..... 

在客户端内部控制器或通过其他答案中显示的任何服务

  $http.get(dataUrl) .success(function (data){ $scope.templateData = data; }) .error(function (error, status){ $scope.data.error = { message: error, status: status}; console.log($scope.data.error.status); if(status == CODE_CONFIGURED_ON_SERVER_SIDE_FOR_NON_LOGGED_IN){ //redirect to login }); 

注意: – 我将在明天或未来更新

app.js

 'use strict'; // Declare app level module which depends on filters, and services var app= angular.module('myApp', ['ngRoute','angularUtils.directives.dirPagination','ngLoadingSpinner']); app.config(['$routeProvider', function($routeProvider) { $routeProvider.when('/login', {templateUrl: 'partials/login.html', controller: 'loginCtrl'}); $routeProvider.when('/home', {templateUrl: 'partials/home.html', controller: 'homeCtrl'}); $routeProvider.when('/salesnew', {templateUrl: 'partials/salesnew.html', controller: 'salesnewCtrl'}); $routeProvider.when('/salesview', {templateUrl: 'partials/salesview.html', controller: 'salesviewCtrl'}); $routeProvider.when('/users', {templateUrl: 'partials/users.html', controller: 'usersCtrl'}); $routeProvider.when('/forgot', {templateUrl: 'partials/forgot.html', controller: 'forgotCtrl'}); $routeProvider.otherwise({redirectTo: '/login'}); }]); app.run(function($rootScope, $location, loginService){ var routespermission=['/home']; //route that require login var salesnew=['/salesnew']; var salesview=['/salesview']; var users=['/users']; $rootScope.$on('$routeChangeStart', function(){ if( routespermission.indexOf($location.path()) !=-1 || salesview.indexOf($location.path()) !=-1 || salesnew.indexOf($location.path()) !=-1 || users.indexOf($location.path()) !=-1) { var connected=loginService.islogged(); connected.then(function(msg){ if(!msg.data) { $location.path('/login'); } }); } }); }); 

loginServices.js

 'use strict'; app.factory('loginService',function($http, $location, sessionService){ return{ login:function(data,scope){ var $promise=$http.post('data/user.php',data); //send data to user.php $promise.then(function(msg){ var uid=msg.data; if(uid){ scope.msgtxt='Correct information'; sessionService.set('uid',uid); $location.path('/home'); } else { scope.msgtxt='incorrect information'; $location.path('/login'); } }); }, logout:function(){ sessionService.destroy('uid'); $location.path('/login'); }, islogged:function(){ var $checkSessionServer=$http.post('data/check_session.php'); return $checkSessionServer; /* if(sessionService.get('user')) return true; else return false; */ } } }); 

sessionServices.js

 'use strict'; app.factory('sessionService', ['$http', function($http){ return{ set:function(key,value){ return sessionStorage.setItem(key,value); }, get:function(key){ return sessionStorage.getItem(key); }, destroy:function(key){ $http.post('data/destroy_session.php'); return sessionStorage.removeItem(key); } }; }]) 

loginCtrl.js

 'use strict'; app.controller('loginCtrl', ['$scope','loginService', function ($scope,loginService) { $scope.msgtxt=''; $scope.login=function(data){ loginService.login(data,$scope); //call login service }; }]); 

您可以使用resolve

 angular.module('app',[]) .config(function($routeProvider) { $routeProvider .when('/', { templateUrl : 'app/views/login.html', controller : 'YourController', controllerAs : 'Your', resolve: { factory : checkLoginRedirect } }) } 

而且,解决的function:

 function checkLoginRedirect($location){ var user = firebase.auth().currentUser; if (user) { // User is signed in. if ($location.path() == "/"){ $location.path('dash'); } return true; }else{ // No user is signed in. $location.path('/'); return false; } } 

Firebase也有一个方法可以帮助你安装一个观察者,我build议在.run里面安装它:

 .run(function(){ firebase.auth().onAuthStateChanged(function(user) { if (user) { console.log('User is signed in.'); } else { console.log('No user is signed in.'); } }); } 

您应该在两个主要站点中检查用户身份validation。

  • 当用户改变状态时,使用'$routeChangeStart'callback来检查它
  • 当$ http请求从angular度发送时,使用拦截器。