AngularJS-每个路由器和控制器中的登录和认证

我有一个 AngularJS 应用程序创建使用文书,步兵和鲍尔。

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

应用程序

'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中,我检查登录信息,如果成功,我将在服务工厂中设置用户对象。我不知道这是否正确。

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

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

我听说过 N- 饼干,但我不知道如何使用它们。

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

223860 次浏览

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

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) ,它将处理用户对象,并有一个方法来知道用户是否被记录。

服务 :

 .factory('Auth', function(){
var user;


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

从你的 app.run,你应该听 $routeChangeStart事件。当路由发生更改时,它将检查用户是否被记录(应该由 isLoggedIn方法处理)。如果用户未被记录,它将不会加载请求的路由,而是将用户重定向到正确的页面(在您的情况下是登录)。

应该在登录页面中使用 loginController来处理登录。它应该只是与 Auth服务进行交互,并设置用户是否记录日志。

登录控制器 :

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

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

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

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

  • 当用户更改状态时,使用 '$routeChangeStart'回调检查它
  • 当一个 $http 请求通过使用拦截器从 angle 发送时。

下面是另一个可能的解决方案,使用 $stateProvider$routeProviderresolve属性:

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

.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负责请求服务器,以了解用户配置文件(例如链接到连接到请求的访问令牌) :

.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, i.e. 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;


}
});


}])

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

.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


}])

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

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


}])

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

我检查用户是否在 $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');
            }
        });
    }
 
})();

例如,一个应用程序有两个名为 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");
}
}
}


});
}]);

所有人都提出了大的解决方案,为什么你担心会议在客户端。 我的意思是,当 state/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 返回。现在开始起作用了,根据用户的登录状态使用服务器返回标准返回类型。检查这些返回代码并在控制器中处理您的请求。 注意:-对于本地不需要 ajax 调用的控制器,您可以像这个 server.location/api/checkSession.php那样调用一个空白请求到服务器,这是 < strong > 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
});

注意:-我会更新更多的明天或在未来

应用程序

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


}]);

为单个路线定义自定义行为的最简单方式是:

1) routes.js: 为任何想要的路线创建一个新的属性(如 requireAuth)

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)如果顶层控制器没有绑定到 ng-view内部的元素(以避免与角 $routeProvider 冲突) ,检查 newUrl是否具有 requireAuth属性并相应地执行操作

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

我觉得这样最简单,但也许只是个人偏好。

当您指定您的登录路由(以及任何其他匿名路由; 例如:/register、/logout、/refshToken 等)时,添加:

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 都是强制认证的应用程序中,这样做的工作量更小。而且更安全; 如果您忘记将其添加到新的 URL 中,最糟糕的情况就是匿名 URL 受到保护。如果您使用另一种方法,指定“ requAuthentication: true”,而忘记将其添加到 URL 中,那么您将向公众泄露一个敏感页面。

然后在您认为最适合您的代码设计的地方运行它。

//I put it right after the main app module config. I.e. 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");
}
});
});

你可以使用 resolve:

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

还有,解决方案的作用是:

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 也有一个方法可以帮助你安装一个观察者,我建议你把它安装在 .run里面:

.run(function(){


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