AngularJS: базовый пример использования аутентификации в одностраничном приложении

100

Я новичок в AngularJS, прошел их руководство и почувствовал его.

У меня есть готовый бэкэнд для моего проекта, где каждая RESTконечная точка должна быть аутентифицирована.

Что я хочу сделать
а.) Я хочу иметь одну страницу для моего проекта http://myproject.com.
б.) Как только пользователь попадает по URL-адресу в браузере, в зависимости от того, вошел ли пользователь в систему или нет, ему предоставляется домашняя страница / представление или страница входа / представление под тем же URL-адресом http://myproject.com.
c.) если пользователь не вошел в систему, он заполняет форму, и сервер устанавливает USER_TOKENсеанс, поэтому все дальнейшие запросы к конечным точкам будут аутентифицированы на основеUSER_TOKEN

Мои затруднения
а. Как я могу обрабатывать аутентификацию на стороне клиента с помощью AngularJS? Я видел здесь и здесь, но не понимал, как их использовать
б.) Как я могу представить пользователю разные представления в зависимости от того, вошел ли пользователь в систему или нет по тому же URL-адресуhttp://myproject.com

Я впервые использую angular.js и действительно не понимаю, с чего начать. Мы очень ценим любые советы и / или ресурсы.

мечтатель
источник
Пожалуйста, ознакомьтесь со статьей ниже frederiknakstad.com/…
Аджай Бенивал
1
@MichaelCalkins просто разместить ссылку неконструктивно. Вы должны хотя бы сказать, что будет по ссылке.
Дэйв Гордон
Мой b: контроль доступа и аутентификация AngularJS coderwall.com/p/f6brkg
Майкл Дж. Калкинс,
У команды OAuth есть отличная библиотека для этого andreareginato.github.io/oauth-ng
Faktor 10,

Ответы:

48

Я создал репозиторий на github, в основном резюмирующий эту статью: https://medium.com/opinionated-angularjs/techniques-for-authentication-in-angularjs-applications-7bbf0346acec

ng-login Репозиторий Github

Plunker

Я постараюсь объяснить как можно лучше, надеюсь, что помогу некоторым из вас:

(1) app.js: создание констант аутентификации в определении приложения.

var loginApp = angular.module('loginApp', ['ui.router', 'ui.bootstrap'])
/*Constants regarding user login defined here*/
.constant('USER_ROLES', {
    all : '*',
    admin : 'admin',
    editor : 'editor',
    guest : 'guest'
}).constant('AUTH_EVENTS', {
    loginSuccess : 'auth-login-success',
    loginFailed : 'auth-login-failed',
    logoutSuccess : 'auth-logout-success',
    sessionTimeout : 'auth-session-timeout',
    notAuthenticated : 'auth-not-authenticated',
    notAuthorized : 'auth-not-authorized'
})

(2) Служба аутентификации : все следующие функции реализованы в службе auth.js. Служба $ http используется для связи с сервером для процедур аутентификации. Также содержит функции по авторизации, то есть если пользователю разрешено совершать определенное действие.

angular.module('loginApp')
.factory('Auth', [ '$http', '$rootScope', '$window', 'Session', 'AUTH_EVENTS', 
function($http, $rootScope, $window, Session, AUTH_EVENTS) {

authService.login() = [...]
authService.isAuthenticated() = [...]
authService.isAuthorized() = [...]
authService.logout() = [...]

return authService;
} ]);

(3) Сессия: синглтон для хранения пользовательских данных. Реализация здесь зависит от вас.

angular.module('loginApp').service('Session', function($rootScope, USER_ROLES) {

    this.create = function(user) {
        this.user = user;
        this.userRole = user.userRole;
    };
    this.destroy = function() {
        this.user = null;
        this.userRole = null;
    };
    return this;
});

(4) Родительский контроллер: считайте это «основной» функцией вашего приложения, все контроллеры наследуются от этого контроллера, и это основа аутентификации этого приложения.

<body ng-controller="ParentController">
[...]
</body>

(5) Контроль доступа: чтобы запретить доступ на определенных маршрутах, необходимо выполнить 2 шага:

a) Добавьте данные о ролях, которым разрешен доступ к каждому маршруту, в сервисе $ stateProvider ui router, как показано ниже (то же самое может работать и для ngRoute).

.config(function ($stateProvider, USER_ROLES) {
  $stateProvider.state('dashboard', {
    url: '/dashboard',
    templateUrl: 'dashboard/index.html',
    data: {
      authorizedRoles: [USER_ROLES.admin, USER_ROLES.editor]
    }
  });
})

б) В $ rootScope. $ on ('$ stateChangeStart') добавьте функцию для предотвращения изменения состояния, если пользователь не авторизован.

$rootScope.$on('$stateChangeStart', function (event, next) {
    var authorizedRoles = next.data.authorizedRoles;
    if (!Auth.isAuthorized(authorizedRoles)) {
      event.preventDefault();
      if (Auth.isAuthenticated()) {
        // user is not allowed
        $rootScope.$broadcast(AUTH_EVENTS.notAuthorized);
      } else {
        // user is not logged in
        $rootScope.$broadcast(AUTH_EVENTS.notAuthenticated);
      }
    }
});

(6) Перехватчик аутентификации: это реализовано, но не может быть проверено в рамках этого кода. После каждого запроса $ http этот перехватчик проверяет код состояния, если возвращается одно из следующих, то он транслирует событие, чтобы заставить пользователя снова войти в систему.

angular.module('loginApp')
.factory('AuthInterceptor', [ '$rootScope', '$q', 'Session', 'AUTH_EVENTS',
function($rootScope, $q, Session, AUTH_EVENTS) {
    return {
        responseError : function(response) {
            $rootScope.$broadcast({
                401 : AUTH_EVENTS.notAuthenticated,
                403 : AUTH_EVENTS.notAuthorized,
                419 : AUTH_EVENTS.sessionTimeout,
                440 : AUTH_EVENTS.sessionTimeout
            }[response.status], response);
            return $q.reject(response);
        }
    };
} ]);

PS Ошибку с автозаполнением данных формы, о которой говорилось в 1-й статье, можно легко избежать, добавив директиву, которая включена в directives.js.

PS2 Этот код может быть легко изменен пользователем, чтобы разрешить просмотр различных маршрутов или отображение содержимого, которое не предназначалось для отображения. Логика ДОЛЖНА быть реализована на стороне сервера, это просто способ правильно показать вещи в вашем ng-приложении.

Алекс Арванитидис
источник
1
Я следил за вашим руководством, чтобы погрузиться в логику на стороне клиента. Это действительно хорошо!! Я кое-что упустил из-за ручного уничтожения сессий, но мы тоже должны экспериментировать и ломать вещи!
Sebastialonso
~~ не уверен, правильно ли я понимаю эту строку: authService.login() = [...]эти квадратные скобки будут означать что-то вроде $http.get(url, {uID, pwd}? ~~ хорошо, заглянул в плункер, это было, как я сказал XD
netalex
1
Можете ли вы расширить свой ответ для серверной части?
запрос
25

Мне нравится этот подход, и я реализовал его на стороне сервера, не выполняя никаких действий, связанных с аутентификацией, на интерфейсе.

Моя «техника» в моем последнем приложении ... клиент не заботится об Auth. Каждая вещь в приложении требует сначала входа в систему, поэтому сервер всегда обслуживает страницу входа, если в сеансе не обнаружен существующий пользователь. Если session.user найден, сервер просто отправляет index.html. Бам: -о

Ищите комментарий «Эндрю Джослин».

https://groups.google.com/forum/?fromgroups=#!searchin/angular/authentication/angular/POXLTi_JUgg/VwStpoWCPUQJ

мечтатель
источник
3
если это веб-API? Думаю, я не получил вашего ответа :(
Леандро Де Мелло Фагундес
1
Что, если вы хотите отобразить имя пользователя? Или если вы разговариваете со службой с именем пользователя в URL-адресах конечных точек?
Perrygeo
2
извините, но я не понимаю ответа. как вы обрабатываете сеанс в angular? где установлен session.user? не могли бы вы сделать пример этого кода? спасибо
François Romain
4
Сеансы обрабатываются на стороне клиента, а не на стороне сервера, клиент сохраняет токен и отправляет его как часть каждого запроса, который он делает. Сервер проверяет токен и обрабатывает запрос
daydreamer
4
Может ли кто-нибудь, кто понимает это, отредактировать этот ответ для остальных, пожалуйста?
Alojz Janez
14

Я ответил на аналогичный вопрос здесь: AngularJS Authentication + RESTful API


Я написал модуль AngularJS для UserApp, который поддерживает защищенные / общедоступные маршруты, перенаправление при входе / выходе, пульс для проверки статуса, сохраняет токен сеанса в файле cookie, событиях и т. Д.

Вы могли либо:

  1. Измените модуль и прикрепите его к своему собственному API, или
  2. Используйте модуль вместе с UserApp (облачный API для управления пользователями)

https://github.com/userapp-io/userapp-angular

Если вы используете UserApp, вам не придется писать какой-либо серверный код для пользовательского материала (больше, чем проверка токена). Пройдите курс по Codecademy чтобы попробовать.

Вот несколько примеров того, как это работает:

  • Как указать, какие маршруты должны быть общедоступными и какой маршрут является формой входа в систему:

    $routeProvider.when('/login', {templateUrl: 'partials/login.html', public: true, login: true});
    $routeProvider.when('/signup', {templateUrl: 'partials/signup.html', public: true});
    $routeProvider.when('/home', {templateUrl: 'partials/home.html'});

    .otherwise()Маршрут должен быть установлен в положение, где вы хотите , чтобы ваши пользователи будут перенаправлены после входа в систему . Пример:

    $routeProvider.otherwise({redirectTo: '/home'});

  • Форма входа с обработкой ошибок:

    <form ua-login ua-error="error-msg">
        <input name="login" placeholder="Username"><br>
        <input name="password" placeholder="Password" type="password"><br>
        <button type="submit">Log in</button>
        <p id="error-msg"></p>
    </form>
  • Форма регистрации с обработкой ошибок:

    <form ua-signup ua-error="error-msg">
      <input name="first_name" placeholder="Your name"><br>
      <input name="login" ua-is-email placeholder="Email"><br>
      <input name="password" placeholder="Password" type="password"><br>
      <button type="submit">Create account</button>
      <p id="error-msg"></p>
    </form>
  • Ссылка для выхода:

    <a href="#" ua-logout>Log Out</a>

    (Завершает сеанс и перенаправляет на маршрут входа)

  • Доступ к свойствам пользователя:

    Доступ к свойствам пользователя осуществляется с помощью userслужбы, например:user.current.email

    Или в шаблоне: <span>{{ user.email }}</span>

  • Скрыть элементы, которые должны быть видны только при входе в систему:

    <div ng-show="user.authorized">Welcome {{ user.first_name }}!</div>

  • Показать элемент на основе разрешений:

    <div ua-has-permission="admin">You are an admin</div>

А для аутентификации в серверных службах просто используйте, user.token()чтобы получить токен сеанса и отправить его с запросом AJAX. На бэкэнде используйте UserApp API (если вы используете UserApp), чтобы проверить, действителен ли токен.

Если вам понадобится помощь, просто дайте мне знать!

Тимоти Э. Йоханссон
источник
Как мне «Изменить модуль и прикрепить его к своему собственному API» ?
Pureferret 03
2

В angularjs вы можете создать часть пользовательского интерфейса, службу, директивы и все части angularjs, которые представляют пользовательский интерфейс. Это хорошая технология, над которой можно работать.

Как и любой, кто впервые знаком с этой технологией и хочет аутентифицировать «пользователя», я предлагаю сделать это с помощью веб-API C #. для этого вы можете использовать спецификацию OAuth, которая поможет вам создать надежный механизм безопасности для аутентификации пользователя. как только вы создадите WebApi с помощью OAuth, вам нужно будет вызвать этот api для токена:

var _login = function (loginData) {
 
        var data = "grant_type=password&username=" + loginData.userName + "&password=" + loginData.password;
 
        var deferred = $q.defer();
 
        $http.post(serviceBase + 'token', data, { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }).success(function (response) {
 
            localStorageService.set('authorizationData', { token: response.access_token, userName: loginData.userName });
 
            _authentication.isAuth = true;
            _authentication.userName = loginData.userName;
 
            deferred.resolve(response);
 
        }).error(function (err, status) {
            _logOut();
            deferred.reject(err);
        });
 
        return deferred.promise;
 
    };
 

и как только вы получите токен, вы запрашиваете ресурсы у angularjs с помощью токена и получаете доступ к ресурсу, который защищен в веб-Api со спецификацией OAuth.

Пожалуйста, загляните в следующую статью для получения дополнительной помощи: -

http://bitoftech.net/2014/06/09/angularjs-token-authentication-using-asp-net-web-api-2-owin-asp-net-identity/

Гуруприт
источник
1

Я думаю, что каждый ответ JSON должен содержать свойство (например, {authenticated: false}), и клиент должен проверять его каждый раз: если false, то контроллер / служба Angular будет «перенаправлять» на страницу входа.

А что будет, если пользователь поймает JSON и изменит значение bool на True?

Я думаю, вам никогда не следует полагаться на клиентскую сторону, чтобы делать подобные вещи. Если пользователь не аутентифицирован, сервер должен просто перенаправить на страницу входа / ошибки.

Doum
источник
2
Проверьте это: github.com/witoldsz/angular-http-auth - перехватчик проверяет код состояния ответа сервера, и если он 403 («требуется вход в систему»), он транслирует событие, поэтому вы можете поймать его внутри приложения и отобразить поле входа.
aherok
10
Перестаньте отвечать друг другу, используя ответы. Вот для чего нужны комментарии!
Soviut
Предложение @aherok, ваш комментарий должен быть повышен до ответа, он будет поставлен на первое место вовремя. остальное просто шум.
user237419 04
0

var _login = function (loginData) {
 
        var data = "grant_type=password&username=" + loginData.userName + "&password=" + loginData.password;
 
        var deferred = $q.defer();
 
        $http.post(serviceBase + 'token', data, { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }).success(function (response) {
 
            localStorageService.set('authorizationData', { token: response.access_token, userName: loginData.userName });
 
            _authentication.isAuth = true;
            _authentication.userName = loginData.userName;
 
            deferred.resolve(response);
 
        }).error(function (err, status) {
            _logOut();
            deferred.reject(err);
        });
 
        return deferred.promise;
 
    };
 

Нвер Абгарян
источник