AngularJS - проверка подлинности пользователя, а затем маршрутизация на правильную страницу
Что я хочу делать, когда пользователь приходит на страницу index.html Мне нужен модуль входа в систему, чтобы сделать 2 вещи:
-
Мне нужно это, чтобы проверить, прошел ли аутентификация пользователя (что, я думаю, я уже начал с "function authService" ), если у пользователя есть действительный токен, затем измените ui-view на dashboard/dashboard.html и если ключ недействителен или вообще нет ключа, загрузите login/login.html в ui-view.
-
Как только они успешно вошли в систему, я хочу, чтобы они были перенаправлены на "dashboard/dashboard.html"
Вот мой логин script:
function authInterceptor(API) {
return {
request: function(config) {
if(config.url.indexOf(API) === 0) {
request.headers = request.headers || {};
request.headers['X-PCC-API-TOKEN'] = localStorage.getItem('token');
}
return config;
}
}
}
function authService(auth) {
var self = this;
self.isAuthed = function() {
localStorage.getItem('token');
}
}
function userService($http, API) {
$http.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;';
$http.defaults.transformRequest = [function(data) {
return angular.isObject(data) && String(data) !== '[object File]' ? param(data) : data;
}];
var self = this;
self.login = function(username, pwd, ctrl) {
ctrl.requestdata = API + '/winauth' + '; with ' + username;
return $http.post(API + '/winauth', {
username: username,
pwd: pwd
})
};
var param = function(obj) {
var query = '', name, value, fullSubName, subName, subValue, innerObj, i;
for(name in obj) {
value = obj[name];
if(value instanceof Array) {
for(i=0; i<value.length; ++i) {
subValue = value[i];
fullSubName = name + '[' + i + ']';
innerObj = {};
innerObj[fullSubName] = subValue;
query += param(innerObj) + '&';
}
}
else if(value instanceof Object) {
for(subName in value) {
subValue = value[subName];
fullSubName = name + '[' + subName + ']';
innerObj = {};
innerObj[fullSubName] = subValue;
query += param(innerObj) + '&';
}
}
else if(value !== undefined && value !== null)
query += encodeURIComponent(name) + '=' + encodeURIComponent(value) + '&';
}
return query.length ? query.substr(0, query.length - 1) : query;
};
}
function LoginCtrl(user) {
var self = this;
function handleRequest(res) {
self.responsedata = res;
self.message = res.data.message;
var authToken = res.data.auth_token;
localStorage.setItem('token', authToken);
}
self.login = function() {
this.requestdata = 'Starting request...';
user.login(self.username, self.pwd, self)
.then(handleRequest, handleRequest)
}
}
// Login Module
var login = angular.module('login', ["ui.router"])
login.factory('authInterceptor', authInterceptor)
login.service('user', userService)
login.service('auth', authService)
login.constant('API', 'http://myserver.com/api')
EDIT - Я добавил это в свой контроллер входа, чтобы указать маршруты входа
login.config(function($httpProvider, $stateProvider, $urlRouterProvider) {
$httpProvider.interceptors.push('authInterceptor');
$urlRouterProvider.otherwise('/login');
$stateProvider
// HOME STATES AND NESTED VIEWS ========================================
.state('login', {
url: '/login',
templateUrl: 'login/login.html',
controller: "mainLogin",
controllerAs: "log"
})
// nested list with just some random string data
.state('dashboard', {
url: '/dashboard',
templateUrl: 'dashboard/dashboard.html',
})
})
login.controller('mainLogin', LoginCtrl)
Вот мой index.html:
EDIT - Я удалил "ng-include" и добавил "ng-view" для управления маршрутами.
<body ng-app="login" ng-controller="mainLogin as log" class="loginPage">
<div class="main" ui-view></div>
</body>
Как вы можете видеть, у меня есть функция, которая проверяет токен в локальном хранилище пользователей:
function authService(auth) {
var self = this;
self.isAuthed = function() {
localStorage.getItem('token');
}
}
И я загружаю его в модуль как услугу:
login.service('auth', authService)
Вот где я застрял. Я не знаю, куда идти отсюда. Я даже не знаю, правильно ли использую функцию authService. Я все еще многому учусь об AngularJS, поэтому мне легко застрять.:)
Еще одна вещь, которую вы заметите, - это мой файл index.html. Я просто по умолчанию загружаю "login/login.html". Мне нужно загрузить либо login.html, либо dashboard.html в зависимости от того, вошли ли они в систему или нет. А затем также проведите их до dashboard.html, как только они успешно войдут в систему.
script отлично работает, ударяя API аутентификации, аутентифицируя пользователя, а затем сохраняя действительный ключ авторизации в своем локальном хранилище.
Кто-нибудь знает, как я могу это сделать?
Ответы
Ответ 1
Есть две отдельные проблемы, с которыми вы сталкиваетесь. Во-первых, это возможность определить, если вы вошли в систему. Предполагая, что пользователь должен войти в систему для любого состояния, кроме состояния входа, вы бы реализовали его так, прослушивая события $stateChangeState и проверяя, что пользователь зарегистрирован в:
login.run(function($state, authService) {
$rootScope.$on('$stateChangeStart', function (event, toState, toParams, fromState, fromParams) {
var authToken = authService.isAuthed();
if (!authToken && toState !== 'login') {
//not logged in, so redirect to the login view instead of the view
//the user was attempting to load
event.preventDefault();
$state.go('login');
}
})
});
Это поместит их в состояние входа, если они еще не вошли в систему.
Вторая часть - перенаправить на правильный вид после входа в систему, который вы сделали бы в своем контроллере входа:
function LoginCtrl(user, $state) {
var self = this;
function handleRequest(res) {
self.responsedata = res;
self.message = res.data.message;
var authToken = res.data.auth_token;
localStorage.setItem('token', authToken);
//after successful login, redirect to dashboard
$state.go('dashboard');
}
self.login = function() {
this.requestdata = 'Starting request...';
user.login(self.username, self.pwd, self)
.then(handleRequest, handleRequest)
}
}
Ответ 2
ok Я вижу, что вы используете ui.router, поэтому давайте работать в этой структуре.
Вы хотите
- проверить, зарегистрирован ли пользователь
- перенаправить пользователя в представление
То, что вы ищете, это resolve:{loggedIn: checkLoggedInFn}
чтобы ваш маршрут для панели инструментов мог быть чем-то вроде
.state('dashboard', {
url: '/dashboard',
templateUrl: 'dashboard/dashboard.html',
resolve: {
loggedIn: function(){
//do your checking here
}
}
})
что в основном состоит в том, что контроллер не будет создавать экземпляр до тех пор, пока не будет разрешено любое решение (так что вы можете использовать обещание здесь, например), а затем значение передается в контроллер как параметр, поэтому вы могли бы что-то сделать как:
if(!loggedIn){
$state.go('login');
}
Ответ 3
Вы можете обрабатывать логику внутри своего логина входа в систему:
self.login = function() {
this.requestdata = 'Starting request...';
user.login(self.username, self.pwd, self)
.then(handleRequest, handleRequest)
}
Внутри обратного вызова для успеха при входе в систему вы просто сделаете изменение состояния, чтобы отправить пользователя в правильное состояние.
Ответ 4
В authInterceptor добавьте код для ответа. Итак:
return {
request: function(config) {
if(config.url.indexOf(API) === 0) {
request.headers = request.headers || {};
request.headers['X-PCC-API-TOKEN'] = localStorage.getItem('token');
}
return config;
},
response: function(response) {
//ok response - code 200
return response;
},
responseError: function(response){
//wrong response - different response code
}
};
На стороне сервера проверьте HTTP-заголовок X-PCC-API-TOKEN, а если нет (отсутствие аутентификации), ответ должен иметь другой код, например 403. Таким образом, метод responseError будет работать в перехватчике.
responseError: function(response){
//wrong response - different response code
if (response.status === 403) {
alert("No rights to page");//your code for no auth
//redirect to different route
$injector.get('$state').transitionTo('login');//use injector service
return $q.reject(response);//return rejection - use $q
}
}
Ответ 5
Ваш сервис прекрасен, и он находится в модуле loginModule, но вы не используете его нигде, где я могу видеть. Вам нужно ввести свою службу в контроллер, чтобы делать то, что вы хотите. В вашем authService вы получаете элемент из localstorage, но вы ничего не возвращаете, например, у вас есть служба входа в систему
function authService(auth) {
var self = this;
self.isAuthed = function() {
return localStorage.getItem('token');
}
}
//here you can inject your auth service to get it work as you want
function LoginCtrl(user, auth) {
var self = this;
function handleRequest(res) {
self.responsedata = res;
self.message = res.data.message;
var authToken = res.data.auth_token;
localStorage.setItem('token', authToken);
}
self.login = function() {
this.requestdata = 'Starting request...';
user.login(self.username, self.pwd, self)
.then(handleRequest, handleRequest)
}
}
login.service('auth', authService)
Ответ 6
function authService(auth) {
var self = this;
self.isAuthed = function() {
**localStorage.getItem('token');**
}
}
Где вы получаете элемент localstorage? Недостаток LValue отсутствует.
На самом базовом уровне вы можете обработать чек для этого элемента - токена - на странице Dashboard во время загрузки страницы и если она равна null, т.е. пустым, затем перенаправить/направить пользователя на страницу входа. Btw, используйте sessionStorage, а не localStorage, поскольку первая будет скрываться, как только закрывается сеанс браузера.
Есть более элегантные и более простые способы достижения этого, например Passport. вы проверили? Это так просто:
app.post('/login', passport.authenticate('local', { successRedirect: '/',
failureRedirect:'/login'}));
Ответ 7
Ваш код не проверяет изменения URL или затрагивает маршруты поперечным способом.
Помните, что аутентификация и авторизация являются сквозными проблемами. При этом Angular имеет возможность перехватить вызовы маршрутизации, прослушивая $routeChangeStart. Ваш "перехватчик" должен быть добавлен туда. Затем вы можете перенаправить маршрутизатор на требуемый вид, выполнив ручную маршрутизацию. Посмотрите как решение из предыдущего потока.
Ответ 8
Существует простой способ добиться того, что вы хотите для своего приложения, используя PassportJs.
Документация довольно проста и проста в реализации.
Вы также можете ссылаться на этот учебник для реализации проверки подлинности с использованием Passport. В этом учебном пособии очень просто, как сделать аутентификацию для вашего приложения.
Ответ 9
Простым способом это просто использовать https://github.com/Emallates/ng-enoa-auth. Вам просто нужно включить его в свое приложение, ничего больше.