Saya sedang dalam proses membuat demo yang lebih bagus serta membersihkan beberapa layanan ini menjadi modul yang dapat digunakan, tapi inilah yang saya buat. Ini adalah proses kompleks untuk mengatasi beberapa peringatan, jadi bertahanlah di sana. Anda harus memecah ini menjadi beberapa bagian.
Lihatlah bagian ini .
Pertama, Anda memerlukan layanan untuk menyimpan identitas pengguna. Saya menyebutnya principal
. Itu dapat diperiksa untuk melihat apakah pengguna login, dan atas permintaan, itu dapat menyelesaikan objek yang mewakili informasi penting tentang identitas pengguna. Ini bisa berupa apa pun yang Anda butuhkan, tetapi yang terpenting adalah nama tampilan, nama pengguna, mungkin email, dan peran yang dimiliki pengguna (jika ini berlaku untuk aplikasi Anda). Kepala sekolah juga memiliki metode untuk melakukan pengecekan peran.
.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;
}
};
}
])
Kedua, Anda memerlukan layanan yang memeriksa keadaan yang ingin dituju pengguna, memastikan mereka masuk (jika perlu; tidak perlu untuk masuk, mengatur ulang kata sandi, dll.), Lalu melakukan pengecekan peran (jika aplikasi Anda butuh ini). Jika tidak diautentikasi, kirim ke halaman masuk. Jika mereka diautentikasi, tetapi gagal pemeriksaan peran, kirim mereka ke halaman akses ditolak. Saya memanggil layanan ini 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');
}
}
});
}
};
}
])
Sekarang semua yang perlu Anda lakukan yaitu mendengarkan pada ui-router
's $stateChangeStart
. Ini memberi Anda kesempatan untuk memeriksa keadaan saat ini, keadaan yang ingin mereka tuju, dan memasukkan cek otorisasi Anda. Jika gagal, Anda dapat membatalkan transisi rute, atau mengubah ke rute lain.
.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();
});
}
]);
Bagian yang sulit tentang melacak identitas pengguna adalah mencarinya jika Anda sudah mengautentikasi (katakanlah, Anda mengunjungi halaman setelah sesi sebelumnya, dan menyimpan token autentikasi dalam cookie, atau mungkin Anda sulit menyegarkan halaman, atau dijatuhkan ke URL dari tautan). Karena cara ui-router
kerjanya, Anda perlu menyelesaikan identitas Anda satu kali, sebelum pemeriksaan auth. Anda dapat melakukan ini menggunakan resolve
opsi di konfigurasi keadaan Anda. Saya memiliki satu negara induk untuk situs yang mewarisi semua negara bagian, yang memaksa kepala sekolah untuk diselesaikan sebelum hal lain terjadi.
$stateProvider.state('site', {
'abstract': true,
resolve: {
authorize: ['authorization',
function(authorization) {
return authorization.authorize();
}
]
},
template: '<div ui-view />'
})
Ada masalah lain di sini ... resolve
hanya dipanggil sekali. Setelah janji Anda untuk pencarian identitas selesai, itu tidak akan menjalankan delegasi ketetapan lagi. Jadi kami harus melakukan pemeriksaan autentikasi Anda di dua tempat: satu kali sesuai dengan janji identitas Anda yang diselesaikan, yang mencakup resolve
pertama kali aplikasi Anda dimuat, dan satu kali lagi $stateChangeStart
jika resolusi telah dilakukan, yang mencakup setiap saat Anda menavigasi ke seluruh negara bagian.
OK, jadi apa yang telah kita lakukan sejauh ini?
- Kami memeriksa untuk melihat kapan aplikasi dimuat jika pengguna masuk.
- Kami melacak info tentang pengguna yang masuk.
- Kami mengarahkan mereka untuk masuk ke negara bagian yang mengharuskan pengguna untuk masuk.
- Kami mengarahkan mereka ke status akses yang ditolak jika mereka tidak memiliki izin untuk mengaksesnya.
- Kami memiliki mekanisme untuk mengarahkan pengguna kembali ke keadaan semula yang mereka minta, jika kami membutuhkan mereka untuk masuk.
- Kami dapat mengeluarkan pengguna (perlu terhubung dengan klien atau kode server apa pun yang mengelola tiket auth) Anda.
- Kami tidak perlu mengirim pengguna kembali ke halaman masuk setiap kali mereka memuat ulang browser mereka atau menjatuhkan tautan.
Kemana kita pergi dari sini? Nah, Anda dapat mengatur negara Anda ke daerah yang membutuhkan tanda. Anda dapat meminta dikonfirmasi / pengguna yang berwenang dengan menambahkan data
dengan roles
ke negara-negara ini (atau orang tua dari mereka, jika Anda ingin menggunakan warisan). Di sini, kami membatasi sumber daya untuk Admin:
.state('restricted', {
parent: 'site',
url: '/restricted',
data: {
roles: ['Admin']
},
views: {
'content@': {
templateUrl: 'restricted.html'
}
}
})
Sekarang Anda dapat mengontrol negara-oleh-negara apa yang pengguna dapat mengakses rute. Ada masalah lain? Mungkin hanya memvariasikan sebagian dari tampilan berdasarkan apakah mereka masuk atau tidak? Tidak masalah. Gunakan principal.isAuthenticated()
atau bahkanprincipal.isInRole()
dengan salah satu dari banyak cara Anda dapat menampilkan suatu template atau elemen secara kondisional.
Pertama, menyuntikkan principal
ke controller atau apa pun, dan menempelkannya ke ruang lingkup sehingga Anda dapat menggunakannya dengan mudah dalam pandangan Anda:
.scope('HomeCtrl', ['$scope', 'principal',
function($scope, principal)
{
$scope.principal = principal;
});
Tampilkan atau sembunyikan elemen:
<div ng-show="principal.isAuthenticated()">
I'm logged in
</div>
<div ng-hide="principal.isAuthenticated()">
I'm not logged in
</div>
Dll, begitu seterusnya, sebagainya. Bagaimanapun, dalam contoh aplikasi Anda, Anda akan memiliki keadaan untuk beranda yang akan membiarkan pengguna yang tidak diauthentikasi mampir. Mereka dapat memiliki tautan ke status masuk atau mendaftar, atau memiliki formulir yang dimasukkan ke dalam halaman itu. Apapun yang cocok untukmu.
Halaman dasbor semua bisa mewarisi dari keadaan yang mengharuskan pengguna untuk masuk dan, katakanlah, menjadi anggota User
peran. Semua hal otorisasi yang telah kita diskusikan akan mengalir dari sana.