[angularjs] 조건에 따라 특정 경로로 리디렉션
로그인보기와 메인보기가있는 작은 AngularJS 앱을 작성 중입니다.
$routeProvider
.when('/main' , {templateUrl: 'partials/main.html', controller: MainController})
.when('/login', {templateUrl: 'partials/login.html', controller: LoginController})
.otherwise({redirectTo: '/login'});
내 LoginController는 사용자 / 패스 조합을 확인하고이를 반영하여 $ rootScope에 속성을 설정합니다.
function LoginController($scope, $location, $rootScope) {
$scope.attemptLogin = function() {
if ( $scope.username == $scope.password ) { // test
$rootScope.loggedUser = $scope.username;
$location.path( "/main" );
} else {
$scope.loginError = "Invalid user/pass.";
}
}
모든 것이 작동하지만 액세스 http://localhost/#/main
하면 로그인 화면을 우회합니다. “루트가 변경 될 때마다 $ rootScope.loggedUser가 null이면 / login으로 경로 재 지정”과 같은 내용을 작성하고 싶었습니다.
…
… 잠깐만 어떻게 든 경로 변경을들을 수 있습니까? 어쨌든이 질문을 게시하고 계속 볼 것입니다.
답변
일부 문서와 소스 코드를 살펴본 후 작동한다고 생각합니다. 아마도 이것은 다른 사람에게 유용할까요?
모듈 구성에 다음을 추가했습니다.
angular.module(...)
.config( ['$routeProvider', function($routeProvider) {...}] )
.run( function($rootScope, $location) {
// register listener to watch route changes
$rootScope.$on( "$routeChangeStart", function(event, next, current) {
if ( $rootScope.loggedUser == null ) {
// no logged user, we should be going to #login
if ( next.templateUrl != "partials/login.html" ) {
// not going to #login, we should redirect now
$location.path( "/login" );
}
}
});
})
이상한 것 하나 login.html
는 “다음”Route 객체에 URL이나 다른 것이 없기 때문에 부분 이름 ( ) 을 테스트 해야한다는 것입니다. 더 좋은 방법이 있을까요?
답변
다음은 ‘해결’구성 속성과 데이터에 따라 라우팅 및 라우팅 규칙에 대한 최종 데이터로드를 가능하게하는 ‘약속 성’을 갖춘보다 우아하고 유연한 솔루션입니다.
라우팅 설정에서 ‘해결’에 기능을 지정하고 데이터를로드 및 확인하는 기능에 모든 리디렉션을 수행하십시오. 데이터를로드 해야하는 경우 리디렉션을 수행 해야하는 경우 약속을 반환합니다. 모든 세부 사항은 $ routerProvider 및 $ q 문서 페이지 에서 찾을 수 있습니다 .
'use strict';
var app = angular.module('app', [])
.config(['$routeProvider', function($routeProvider) {
$routeProvider
.when('/', {
templateUrl: "login.html",
controller: LoginController
})
.when('/private', {
templateUrl: "private.html",
controller: PrivateController,
resolve: {
factory: checkRouting
}
})
.when('/private/anotherpage', {
templateUrl:"another-private.html",
controller: AnotherPriveController,
resolve: {
factory: checkRouting
}
})
.otherwise({ redirectTo: '/' });
}]);
var checkRouting= function ($q, $rootScope, $location) {
if ($rootScope.userProfile) {
return true;
} else {
var deferred = $q.defer();
$http.post("/loadUserProfile", { userToken: "blah" })
.success(function (response) {
$rootScope.userProfile = response.userProfile;
deferred.resolve(true);
})
.error(function () {
deferred.reject();
$location.path("/");
});
return deferred.promise;
}
};
러시아어를 사용하는 사람들을 위해 habr ” Вариант условного раутинга в AngularJS “에 대한 게시물이 있습니다.
답변
나는 똑같이하려고 노력했다. 동료와 작업 한 후 더 간단한 다른 솔루션을 찾았습니다. 에 시계가 설치되어 있습니다 $location.path()
. 그 트릭을 수행합니다. 방금 AngularJS를 배우기 시작했으며 더 깨끗하고 읽기 쉽습니다.
$scope.$watch(function() { return $location.path(); }, function(newValue, oldValue){
if ($scope.loggedIn == false && newValue != '/login'){
$location.path('/login');
}
});
답변
로그인 리디렉션을 구현하는 다른 방법은 여기에 설명 된대로 이벤트와 인터셉터를 사용하는 것 입니다. 이 기사에서는 로그인이 필요한시기를 감지하고 요청을 큐에 넣은 후 로그인에 성공하면 다시 재생하는 등의 추가 이점에 대해 설명합니다.
답변
1. 글로벌 현재 사용자를 설정하십시오.
인증 서비스에서 현재 인증 된 사용자를 루트 범위에서 설정하십시오.
// AuthService.js
// auth successful
$rootScope.user = user
2. 보호 된 각 경로에 인증 기능을 설정하십시오.
// AdminController.js
.config(function ($routeProvider) {
$routeProvider.when('/admin', {
controller: 'AdminController',
auth: function (user) {
return user && user.isAdmin
}
})
})
3. 각 경로 변경에 대한 인증을 확인하십시오.
// index.js
.run(function ($rootScope, $location) {
$rootScope.$on('$routeChangeStart', function (ev, next, curr) {
if (next.$$route) {
var user = $rootScope.user
var auth = next.$$route.auth
if (auth && !auth(user)) { $location.path('/') }
}
})
})
또는 사용자 객체에 대한 권한을 설정하고 각 경로에 권한을 할당 한 다음 이벤트 콜백에서 권한을 확인할 수 있습니다.
답변
누군가를 도울 수 있도록 내가 한 방법은 다음과 같습니다.
구성 publicAccess
에서 공개 또는 공개하려는 몇 가지 경로에 속성을 설정했습니다 (로그인 또는 등록)
$routeProvider
.when('/', {
templateUrl: 'views/home.html',
controller: 'HomeCtrl'
})
.when('/login', {
templateUrl: 'views/login.html',
controller: 'LoginCtrl',
publicAccess: true
})
그런 다음 실행 블록 에서 사용자에게 액세스 권한이 없거나 경로에 공개적으로 액세스 할 수없는 경우 $routeChangeStart
리디렉션 되는 이벤트에 리스너를 설정했습니다 '/login'
.
angular.module('myModule').run(function($rootScope, $location, user, $route) {
var routesOpenToPublic = [];
angular.forEach($route.routes, function(route, path) {
// push route onto routesOpenToPublic if it has a truthy publicAccess value
route.publicAccess && (routesOpenToPublic.push(path));
});
$rootScope.$on('$routeChangeStart', function(event, nextLoc, currentLoc) {
var closedToPublic = (-1 === routesOpenToPublic.indexOf($location.path()));
if(closedToPublic && !user.isLoggedIn()) {
$location.path('/login');
}
});
})
분명히 조건을 isLoggedIn
다른 것으로 바꿀 수 있습니다 … 다른 방법을 보여주는 것입니다.
답변
인터셉터를 사용하여하고 있습니다. index.html 파일에 추가 할 수있는 라이브러리 파일을 만들었습니다. 이렇게하면 나머지 서비스 요청에 대한 전역 오류 처리가 가능하며 모든 오류를 개별적으로 처리 할 필요는 없습니다. 또한 기본 인증 로그인 라이브러리를 붙여 넣었습니다. 거기에서 401 오류를 확인하고 다른 위치로 리디렉션하는 것을 볼 수 있습니다. lib / ea-basic-auth-login.js 참조
lib / http-error-handling.js
/**
* @ngdoc overview
* @name http-error-handling
* @description
*
* Module that provides http error handling for apps.
*
* Usage:
* Hook the file in to your index.html: <script src="lib/http-error-handling.js"></script>
* Add <div class="messagesList" app-messages></div> to the index.html at the position you want to
* display the error messages.
*/
(function() {
'use strict';
angular.module('http-error-handling', [])
.config(function($provide, $httpProvider, $compileProvider) {
var elementsList = $();
var showMessage = function(content, cl, time) {
$('<div/>')
.addClass(cl)
.hide()
.fadeIn('fast')
.delay(time)
.fadeOut('fast', function() { $(this).remove(); })
.appendTo(elementsList)
.text(content);
};
$httpProvider.responseInterceptors.push(function($timeout, $q) {
return function(promise) {
return promise.then(function(successResponse) {
if (successResponse.config.method.toUpperCase() != 'GET')
showMessage('Success', 'http-success-message', 5000);
return successResponse;
}, function(errorResponse) {
switch (errorResponse.status) {
case 400:
showMessage(errorResponse.data.message, 'http-error-message', 6000);
}
}
break;
case 401:
showMessage('Wrong email or password', 'http-error-message', 6000);
break;
case 403:
showMessage('You don\'t have the right to do this', 'http-error-message', 6000);
break;
case 500:
showMessage('Server internal error: ' + errorResponse.data.message, 'http-error-message', 6000);
break;
default:
showMessage('Error ' + errorResponse.status + ': ' + errorResponse.data.message, 'http-error-message', 6000);
}
return $q.reject(errorResponse);
});
};
});
$compileProvider.directive('httpErrorMessages', function() {
return {
link: function(scope, element, attrs) {
elementsList.push($(element));
}
};
});
});
})();
CSS / http-error-handling.css
.http-error-message {
background-color: #fbbcb1;
border: 1px #e92d0c solid;
font-size: 12px;
font-family: arial;
padding: 10px;
width: 702px;
margin-bottom: 1px;
}
.http-error-validation-message {
background-color: #fbbcb1;
border: 1px #e92d0c solid;
font-size: 12px;
font-family: arial;
padding: 10px;
width: 702px;
margin-bottom: 1px;
}
http-success-message {
background-color: #adfa9e;
border: 1px #25ae09 solid;
font-size: 12px;
font-family: arial;
padding: 10px;
width: 702px;
margin-bottom: 1px;
}
index.html
<!doctype html>
<html lang="en" ng-app="cc">
<head>
<meta charset="utf-8">
<title>yourapp</title>
<link rel="stylesheet" href="css/http-error-handling.css"/>
</head>
<body>
<!-- Display top tab menu -->
<ul class="menu">
<li><a href="#/user">Users</a></li>
<li><a href="#/vendor">Vendors</a></li>
<li><logout-link/></li>
</ul>
<!-- Display errors -->
<div class="http-error-messages" http-error-messages></div>
<!-- Display partial pages -->
<div ng-view></div>
<!-- Include all the js files. In production use min.js should be used -->
<script src="lib/angular114/angular.js"></script>
<script src="lib/angular114/angular-resource.js"></script>
<script src="lib/http-error-handling.js"></script>
<script src="js/app.js"></script>
<script src="js/services.js"></script>
<script src="js/controllers.js"></script>
<script src="js/filters.js"></script>
lib / ea-basic-auth-login.js
로그인에 대해 거의 동일하게 수행 할 수 있습니다. 여기에 리디렉션에 대한 답변이 있습니다 ($ location.path ( “/ login”)).
/**
* @ngdoc overview
* @name ea-basic-auth-login
* @description
*
* Module that provides http basic authentication for apps.
*
* Usage:
* Hook the file in to your index.html: <script src="lib/ea-basic-auth-login.js"> </script>
* Place <ea-login-form/> tag in to your html login page
* Place <ea-logout-link/> tag in to your html page where the user has to click to logout
*/
(function() {
'use strict';
angular.module('ea-basic-auth-login', ['ea-base64-login'])
.config(['$httpProvider', function ($httpProvider) {
var ea_basic_auth_login_interceptor = ['$location', '$q', function($location, $q) {
function success(response) {
return response;
}
function error(response) {
if(response.status === 401) {
$location.path('/login');
return $q.reject(response);
}
else {
return $q.reject(response);
}
}
return function(promise) {
return promise.then(success, error);
}
}];
$httpProvider.responseInterceptors.push(ea_basic_auth_login_interceptor);
}])
.controller('EALoginCtrl', ['$scope','$http','$location','EABase64Login', function($scope, $http, $location, EABase64Login) {
$scope.login = function() {
$http.defaults.headers.common['Authorization'] = 'Basic ' + EABase64Login.encode($scope.email + ':' + $scope.password);
$location.path("/user");
};
$scope.logout = function() {
$http.defaults.headers.common['Authorization'] = undefined;
$location.path("/login");
};
}])
.directive('eaLoginForm', [function() {
return {
restrict: 'E',
template: '<div id="ea_login_container" ng-controller="EALoginCtrl">' +
'<form id="ea_login_form" name="ea_login_form" novalidate>' +
'<input id="ea_login_email_field" class="ea_login_field" type="text" name="email" ng-model="email" placeholder="E-Mail"/>' +
'<br/>' +
'<input id="ea_login_password_field" class="ea_login_field" type="password" name="password" ng-model="password" placeholder="Password"/>' +
'<br/>' +
'<button class="ea_login_button" ng-click="login()">Login</button>' +
'</form>' +
'</div>',
replace: true
};
}])
.directive('eaLogoutLink', [function() {
return {
restrict: 'E',
template: '<a id="ea-logout-link" ng-controller="EALoginCtrl" ng-click="logout()">Logout</a>',
replace: true
}
}]);
angular.module('ea-base64-login', []).
factory('EABase64Login', function() {
var keyStr = 'ABCDEFGHIJKLMNOP' +
'QRSTUVWXYZabcdef' +
'ghijklmnopqrstuv' +
'wxyz0123456789+/' +
'=';
return {
encode: function (input) {
var output = "";
var chr1, chr2, chr3 = "";
var enc1, enc2, enc3, enc4 = "";
var i = 0;
do {
chr1 = input.charCodeAt(i++);
chr2 = input.charCodeAt(i++);
chr3 = input.charCodeAt(i++);
enc1 = chr1 >> 2;
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
enc4 = chr3 & 63;
if (isNaN(chr2)) {
enc3 = enc4 = 64;
} else if (isNaN(chr3)) {
enc4 = 64;
}
output = output +
keyStr.charAt(enc1) +
keyStr.charAt(enc2) +
keyStr.charAt(enc3) +
keyStr.charAt(enc4);
chr1 = chr2 = chr3 = "";
enc1 = enc2 = enc3 = enc4 = "";
} while (i < input.length);
return output;
},
decode: function (input) {
var output = "";
var chr1, chr2, chr3 = "";
var enc1, enc2, enc3, enc4 = "";
var i = 0;
// remove all characters that are not A-Z, a-z, 0-9, +, /, or =
var base64test = /[^A-Za-z0-9\+\/\=]/g;
if (base64test.exec(input)) {
alert("There were invalid base64 characters in the input text.\n" +
"Valid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='\n" +
"Expect errors in decoding.");
}
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
do {
enc1 = keyStr.indexOf(input.charAt(i++));
enc2 = keyStr.indexOf(input.charAt(i++));
enc3 = keyStr.indexOf(input.charAt(i++));
enc4 = keyStr.indexOf(input.charAt(i++));
chr1 = (enc1 << 2) | (enc2 >> 4);
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
chr3 = ((enc3 & 3) << 6) | enc4;
output = output + String.fromCharCode(chr1);
if (enc3 != 64) {
output = output + String.fromCharCode(chr2);
}
if (enc4 != 64) {
output = output + String.fromCharCode(chr3);
}
chr1 = chr2 = chr3 = "";
enc1 = enc2 = enc3 = enc4 = "";
} while (i < input.length);
return output;
}
};
});
})();