더 나은 데모를 만들고 이러한 서비스 중 일부를 사용 가능한 모듈로 정리하는 과정에 있습니다. 그러나 여기에 제가 제시 한 내용이 있습니다. 이는 일부주의 사항을 해결하기위한 복잡한 프로세스이므로 여기에 연결하십시오. 이것을 여러 조각으로 나누어야합니다.
이 펑크를 살펴보십시오 .
먼저, 사용자의 신원을 저장하는 서비스가 필요합니다. 나는 이것을 부른다 principal
. 사용자가 로그인했는지 확인할 수 있으며 요청시 사용자 ID에 대한 필수 정보를 나타내는 개체를 확인할 수 있습니다. 필요한 것은 무엇이든 가능하지만 필수는 표시 이름, 사용자 이름, 전자 메일 및 사용자가 속한 역할 (앱에 적용되는 경우)입니다. 교장은 역할 점검을 수행하는 방법도 있습니다.
.factory('principal', ['$q', '$http', '$timeout',
function($q, $http, $timeout) {
var _identity = undefined,
_authenticated = false;
return {
isIdentityResolved: function() {
return angular.isDefined(_identity);
},
isAuthenticated: function() {
return _authenticated;
},
isInRole: function(role) {
if (!_authenticated || !_identity.roles) return false;
return _identity.roles.indexOf(role) != -1;
},
isInAnyRole: function(roles) {
if (!_authenticated || !_identity.roles) return false;
for (var i = 0; i < roles.length; i++) {
if (this.isInRole(roles[i])) return true;
}
return false;
},
authenticate: function(identity) {
_identity = identity;
_authenticated = identity != null;
},
identity: function(force) {
var deferred = $q.defer();
if (force === true) _identity = undefined;
// check and see if we have retrieved the
// identity data from the server. if we have,
// reuse it by immediately resolving
if (angular.isDefined(_identity)) {
deferred.resolve(_identity);
return deferred.promise;
}
// otherwise, retrieve the identity data from the
// server, update the identity object, and then
// resolve.
// $http.get('/svc/account/identity',
// { ignoreErrors: true })
// .success(function(data) {
// _identity = data;
// _authenticated = true;
// deferred.resolve(_identity);
// })
// .error(function () {
// _identity = null;
// _authenticated = false;
// deferred.resolve(_identity);
// });
// for the sake of the demo, fake the lookup
// by using a timeout to create a valid
// fake identity. in reality, you'll want
// something more like the $http request
// commented out above. in this example, we fake
// looking up to find the user is
// not logged in
var self = this;
$timeout(function() {
self.authenticate(null);
deferred.resolve(_identity);
}, 1000);
return deferred.promise;
}
};
}
])
둘째, 사용자가 가고 싶은 상태를 확인하고 로그인했는지 (필요한 경우, 로그인, 비밀번호 재설정 등에 필요하지 않음) 확인한 다음 역할 확인 (앱이있는 경우)을 수행하는 서비스가 필요합니다 이 필요합니다). 인증되지 않은 경우 로그인 페이지로 보내십시오. 인증되었지만 역할 확인에 실패하면 액세스 거부 페이지로 보내십시오. 이 서비스를 호출합니다 authorization
.
.factory('authorization', ['$rootScope', '$state', 'principal',
function($rootScope, $state, principal) {
return {
authorize: function() {
return principal.identity()
.then(function() {
var isAuthenticated = principal.isAuthenticated();
if ($rootScope.toState.data.roles
&& $rootScope.toState
.data.roles.length > 0
&& !principal.isInAnyRole(
$rootScope.toState.data.roles))
{
if (isAuthenticated) {
// user is signed in but not
// authorized for desired state
$state.go('accessdenied');
} else {
// user is not authenticated. Stow
// the state they wanted before you
// send them to the sign-in state, so
// you can return them when you're done
$rootScope.returnToState
= $rootScope.toState;
$rootScope.returnToStateParams
= $rootScope.toStateParams;
// now, send them to the signin state
// so they can log in
$state.go('signin');
}
}
});
}
};
}
])
이제 모든 사용자는가에 경청 할 필요가 ui-router
의 $stateChangeStart
. 이를 통해 현재 상태, 가고 싶은 상태를 검사하고 권한 확인을 삽입 할 수 있습니다. 실패하면 경로 전환을 취소하거나 다른 경로로 변경할 수 있습니다.
.run(['$rootScope', '$state', '$stateParams',
'authorization', 'principal',
function($rootScope, $state, $stateParams,
authorization, principal)
{
$rootScope.$on('$stateChangeStart',
function(event, toState, toStateParams)
{
// track the state the user wants to go to;
// authorization service needs this
$rootScope.toState = toState;
$rootScope.toStateParams = toStateParams;
// if the principal is resolved, do an
// authorization check immediately. otherwise,
// it'll be done when the state it resolved.
if (principal.isIdentityResolved())
authorization.authorize();
});
}
]);
사용자의 신원을 추적하는 데있어 까다로운 부분은 이미 인증을받은 경우 (예 : 이전 세션 후 페이지를 방문하고 쿠키에 인증 토큰을 저장했거나 페이지를 강제로 새로 고침 한 경우) 확인하는 것입니다. 링크에서 URL로 삭제). ui-router
작동 방식으로 인해 인증 확인 전에 신원 확인을 한 번 수행해야합니다. resolve
상태 구성 의 옵션을 사용하여이 작업을 수행 할 수 있습니다 . 모든 상태가 상속되는 사이트에 대해 하나의 부모 상태가 있으므로 다른 일이 발생하기 전에 교장을 해결해야합니다.
$stateProvider.state('site', {
'abstract': true,
resolve: {
authorize: ['authorization',
function(authorization) {
return authorization.authorize();
}
]
},
template: '<div ui-view />'
})
여기 또 다른 문제가 있습니다 ... resolve
한 번만 호출됩니다. 신원 조회에 대한 약속이 완료되면 해결 대리인을 다시 실행하지 않습니다. 따라서 두 가지 위치에서 인증 확인을 수행해야합니다. 한 번은 아이덴티티 약속 해결에 resolve
따라 (이는 앱이 처음로드 될 때를 포함하고 $stateChangeStart
, 해결이 완료된 경우에 한 번) 상태를 탐색 할 때마다 적용됩니다.
좋아, 지금까지 우리는 무엇을 했는가?
- 사용자가 로그인했는지 앱이 언제로드되는지 확인합니다.
- 로그인 한 사용자에 대한 정보를 추적합니다.
- 사용자가 로그인해야하는 상태에 대해 로그인 상태로 리디렉션합니다.
- 액세스 권한이없는 경우 액세스 거부 상태로 리디렉션합니다.
- 로그인이 필요한 경우 사용자를 요청한 원래 상태로 다시 리디렉션하는 메커니즘이 있습니다.
- 사용자를 로그 아웃 할 수 있습니다 (인증 티켓을 관리하는 모든 클라이언트 또는 서버 코드와 연계하여 연결해야 함).
- 우리는 하지 않습니다 로그인 페이지로 다시 그들의 브라우저를 다시로드하거나 링크를 드롭 할 때마다 사용자를 보내야합니다.
여기서 어디로 가나 요? 글쎄, 당신은 로그인이 필요 지역으로 상태를 구성 할 수 있습니다. 당신은 추가 인증 / 권한이 부여 된 사용자를 요구할 수 data
로 roles
(상속을 사용하려는 경우, 또는 이들의 부모)이 상태로. 여기서는 리소스를 관리자로 제한합니다.
.state('restricted', {
parent: 'site',
url: '/restricted',
data: {
roles: ['Admin']
},
views: {
'content@': {
templateUrl: 'restricted.html'
}
}
})
이제 사용자가 라우트에 액세스 할 수있는 상태를 상태별로 제어 할 수 있습니다. 다른 문제가 있습니까? 로그인 여부에 따라보기의 일부만 다를 수 있습니까? 문제 없어요. 를 사용 principal.isAuthenticated()
하거나 principal.isInRole()
수많은 방법 중 하나를 사용하면 조건부 서식 또는 요소를 표시 할 수 있습니다.
먼저 principal
컨트롤러 또는 다른 것에 주입 하고 스코프에 고정하여보기에서 쉽게 사용할 수 있도록하십시오.
.scope('HomeCtrl', ['$scope', 'principal',
function($scope, principal)
{
$scope.principal = principal;
});
요소 표시 또는 숨기기
<div ng-show="principal.isAuthenticated()">
I'm logged in
</div>
<div ng-hide="principal.isAuthenticated()">
I'm not logged in
</div>
기타 등등. 어쨌든 예제 앱에서는 인증되지 않은 사용자가 방문 할 수있는 홈페이지 상태가됩니다. 로그인 또는 가입 상태에 대한 링크가 있거나 해당 양식을 해당 페이지에 내장 할 수 있습니다. 당신에게 맞는 것이 무엇이든.
대시 보드 페이지는 모두 사용자가 로그인해야하는 상태 (예 : User
역할 구성원) 에서 상속 될 수 있습니다 . 우리가 논의한 모든 인증 항목은 거기서부터 흐릅니다.