Mam aplikację AngularJS stworzoną przy użyciu narzędzi yeoman, grunt i bower.
Mam stronę logowania, na której znajduje się kontroler sprawdzający uwierzytelnianie. Jeśli poświadczenia są poprawne, przekierowuję na stronę główną.
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";
}
}
});
Na stronie głównej mam
<span class="user-info">
<small>Welcome,</small>
{{user.name}}
</span>
<span class="logout"><a href="" ng-click="logoutUser()">Logout</a></span>
W oknie loginController
sprawdzam dane logowania i jeśli się powiedzie, ustawiam obiekt użytkownika w fabryce usług. Nie wiem, czy to prawda, czy nie.
Potrzebuję tego, gdy użytkownik jest zalogowany, ustawia pewną wartość w obiekcie użytkownika, aby wszystkie inne strony mogły uzyskać tę wartość.
Za każdym razem, gdy dojdzie do zmiany trasy, kontroler powinien sprawdzić, czy użytkownik jest zalogowany. Jeśli nie, powinien przekierować do strony logowania. Ponadto, jeśli użytkownik jest już zalogowany i wraca na stronę, powinien przejść do strony głównej. Kontroler powinien również sprawdzić poświadczenia na wszystkich trasach.
Słyszałem o ng-cookies, ale nie wiem, jak ich używać.
Wiele z przykładów, które widziałem, nie było zbyt jasnych i wykorzystywały jakieś role dostępu lub coś w tym rodzaju. Nie chcę tego. Chcę tylko filtr logowania. Czy ktoś może mi dać jakieś pomysły?
routeChangeStart
wywołaniu zwrotnym należy sprawdzić, czy lokalizacja to faktycznie „/ login” i pozwolić na to:if ( $location.path() === "/login" ) return;
Oto inne możliwe rozwiązanie, używając
resolve
atrybutu$stateProvider
lub$routeProvider
. Przykład z$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
rozpatruje lub odrzuca obietnicę w zależności od aktualnych uprawnień użytkownika:.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
kopie obecne właściwości użytkownika, oraz wykonuje$hasRole
,$hasAnyRole
,$isAnonymous
i$isAuthenticated
sposoby logiczny (plus$refresh
metoda wyjaśnione później):.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
jest odpowiedzialny za żądanie serwera, aby poznać profil użytkownika (na przykład powiązany z tokenem dostępu dołączonym do żądania):.service("Auth", ["$http", function ($http) { this.getProfile = function () { return $http.get("api/auth"); }; }])
Oczekuje się, że serwer zwróci taki obiekt JSON podczas żądania
GET api/auth
:{ "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 }
Wreszcie, gdy
Access
odrzuca obietnicę, jeśli ją używaszui.router
,$stateChangeError
zdarzenie zostanie uruchomione :.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; } }); }])
Jeśli używasz
ngRoute
,$routeChangeError
zdarzenie zostanie uruchomione :.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; } }); }])
Dostęp do profilu użytkownika można również uzyskać w kontrolerach:
.state("home", { /* ... */ controller: "HomeController", resolve: { userProfile: "UserProfile" } })
UserProfile
następnie zawiera właściwości zwrócone przez serwer podczas żądaniaGET api/auth
:.controller("HomeController", ["$scope", "userProfile", function ($scope, userProfile) { $scope.title = "Hello " + userProfile.name; // "Hello John Doe" in the example }])
UserProfile
musi być odświeżany, gdy użytkownik loguje się lub wylogowuje, abyAccess
mógł obsługiwać trasy z nowym profilem użytkownika. Możesz przeładować całą stronę lub zadzwonićUserProfile.$refresh()
. Przykład podczas logowania:.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"); }); }; }])
źródło
Najprostszy sposób zdefiniowania niestandardowego zachowania dla poszczególnych tras byłby dość łatwy:
1)
routes.js
: utwórz nową właściwość (lubięrequireAuth
) dla dowolnej żądanej trasyangular.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) W kontrolerze najwyższego poziomu, który nie jest powiązany z elementem wewnątrz
ng-view
(aby uniknąć konfliktu z angular$routeProvider
), sprawdź, czy właściwośćnewUrl
marequireAuth
właściwość i postępuj odpowiednioangular.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"); } }); });
źródło
routes.js
.Kilka miesięcy temu napisałem post o tym, jak skonfigurować rejestrację użytkownika i funkcjonalność logowania w Angular, możesz to sprawdzić na http://jasonwatmore.com/post/2015/03/10/AngularJS-User-Registration-and -Login-Example.aspx
Sprawdzam, czy użytkownik jest zalogowany w
$locationChangeStart
zdarzeniu, oto moja główna aplikacja.js pokazująca to:(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'); } }); } })();
źródło
Wydaje mi się, że ten sposób jest najłatwiejszy, ale może to tylko osobiste preferencje.
Po określeniu trasy logowania (i wszelkich innych tras anonimowych; np. / Register, / logout, / refreshToken itp.), Dodaj:
allowAnonymous: true
Więc coś takiego:
$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 }
Nigdy nie musisz określać „allowAnonymous: false”, jeśli nie jest obecne, przyjmuje się, że podczas sprawdzania jest fałsz. W aplikacji, w której większość adresów URL jest wymuszonych uwierzytelniania, jest to mniej pracy. I bezpieczniejsze; jeśli zapomnisz dodać go do nowego adresu URL, najgorsze, co może się zdarzyć, to ochrona anonimowego adresu URL. Jeśli zrobisz to w inny sposób, określając „requireAuthentication: true” i zapomnisz dodać go do adresu URL, ujawniasz publicznie wrażliwą stronę.
Następnie uruchom to tam, gdzie uważasz, że najlepiej pasuje do Twojego projektu kodu.
//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"); } }); });
źródło
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 }; }]);
źródło
Możesz użyć
resolve
:angular.module('app',[]) .config(function($routeProvider) { $routeProvider .when('/', { templateUrl : 'app/views/login.html', controller : 'YourController', controllerAs : 'Your', resolve: { factory : checkLoginRedirect } }) }
I funkcja rozwiązania:
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 ma również metodę, która pomaga zainstalować obserwatora, radzę zainstalować go w
.run
:.run(function(){ firebase.auth().onAuthStateChanged(function(user) { if (user) { console.log('User is signed in.'); } else { console.log('No user is signed in.'); } }); }
źródło
Na przykład aplikacja ma dwóch użytkowników o nazwach ap i auc. Przekazuję dodatkową właściwość do każdej trasy i obsługuję routing na podstawie danych, które otrzymuję w $ routeChangeStart.
Spróbuj tego:
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"); } } } }); }]);
źródło
Wszyscy zasugerowali duże rozwiązanie, dlaczego martwisz się sesją po stronie klienta. Mam na myśli, kiedy zmienia się stan / adres URL, przypuszczam, że wykonujesz wywołanie ajax, aby załadować dane dla tempelate.
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.
Teraz dane AJAX są zwracane przez serwer przy użyciu dowolnego interfejsu API. Teraz chodziło o zwrócenie standardowych typów zwrotów przy użyciu serwera zgodnie ze statusem zalogowanego użytkownika. Sprawdź te kody zwrotne i przeprowadź swoje żądanie w kontrolerze. Uwaga: - W przypadku kontrolera, który nie wymaga natywnie wywołania ajax, możesz wywołać puste żądanie do serwera w ten sposób,
server.location/api/checkSession.php
a to jest 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.....
Po stronie klienta w kontrolerze lub za pośrednictwem dowolnej usługi, jak pokazano w innych odpowiedziach
$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 });
Uwaga: - jutro lub w przyszłości zaktualizuję więcej
źródło
Powinieneś sprawdzić uwierzytelnianie użytkowników w dwóch głównych witrynach.
'$routeChangeStart'
wywołania zwrotnegoźródło