AngularJS:シングルページアプリケーションで認証を使用する基本的な例


100

私はAngularJSを初めて使用し、彼らのチュートリアルを経験しました。

RESTエンドポイントを認証する必要があるプロジェクトのバックエンドの準備ができています。

私は何をしたい
。)私は自分のプロジェクトのための単一のページを持っていると思いますhttp://myproject.com
b。)ユーザーがブラウザーでURLにアクセスすると、ユーザーがログインしているかどうかに基づいて、同じURLでホームページ/ビューまたはログインページ/ビューが表示されますhttp://myproject.com
c。)ユーザーがログインしていない場合、フォームに記入し、サーバーUSER_TOKENがセッションを設定するため、エンドポイントへの以降のすべてのリクエストは、USER_TOKEN

私の混乱
a。)AngularJSを使用してクライアント側の認証をどのように処理できますか?私はここここを見ましが、それらの使用方法を理解していませんでした
。b。)ユーザーが同じURLでログインしているかどうかに基づいて、ユーザーに異なるビューを表示するにはどうすればよいですか。http://myproject.com

初めてangular.jsを使用していて、開始方法について本当に混乱しています。アドバイスやリソースは大歓迎です。


記事の下のを見てくださいfrederiknakstad.com/...
アジャイBeniwal

1
リンクを配置するだけの@MichaelCalkinsは建設的ではありません。少なくとも、リンクが提供するものを言う必要があります。
Dave Gordon

マイB:AngularJSアクセスコントロールと認証coderwall.com/p/f6brkg
マイケル・J・カルキンズ

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リポジトリ

プランカー

私は可能な限り説明するように努めますが、私はあなた方の何人かを助けることを願っています:

(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)以下に示すように、UIルーターの$ stateProviderサービスで、各ルートへのアクセスを許可されたロールのデータを追加します(ngRouteでも同じことができます)。

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

b)$ 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)Authインターセプター:これは実装されていますが、このコードのスコープでは確認できません。各$ 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-appで正しく表示するための方法です。


1
私はあなたのガイドに従って、クライアント側のロジックに頭を回しました。本当に美味しい!! 手動でセッションを破棄することについて何かを見逃しましたが、私たちは実験し、物事を壊さなければなりません!
Sebastialonso

~~私がその行を正しく理解しているかどうかわからない:authService.login() = [...]これらの角かっこは$http.get(url, {uID, pwd}?~~のようなものを表します、プランカーを調べたところ、XDと言った
とおりでした

1
サーバー側の答えを広げることができますか?
クエリ

25

私はアプローチが好きで、フロントエンドで認証関連のことをせずにサーバー側に実装しました

私の最新アプリの「テクニック」は..クライアントはAuthを気にしません。アプリ内のすべてのものは最初にログインを必要とするため、セッションで既存のユーザーが検出されない限り、サーバーは常にログインページを提供します。session.userが見つかった場合、サーバーは単にindex.htmlを送信します。バム:-o

「Andrew Joslin」のコメントを探してください。

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


3
それがウェブAPIなら?私はあなたの答えを得られなかったと思います:(
Leandro De Mello Fagundes 2013

1
ユーザー名を表示したい場合はどうしますか?または、エンドポイントURLのユーザー名を使用してサービスと話している場合は、
perrygeo 2013

2
すみませんが、答えがわかりません。どのように角度でセッションを処理しますか?session.userはどこに設定されていますか?これのコード例を作っていただけませんか?ありがとう
フランソワ・ロメイン

4
セッションはサーバー側ではなくクライアント側で処理され、クライアントはトークンを保存して、それが行うすべてのリクエストの一部として送信します。サーバーはトークンを検証し、リクエストを処理します
Daydreamer

4
それを理解している誰かがこの答えを編集してくれませんか?
Alojz Janez 2014年

14

私はここで同様の質問に答えました:AngularJS Authentication + RESTful API


私が書いたAngularJSモジュールUserApp支持体には、上の再ルーティング/公共のルートを、保護することをログイン/ログアウト、ステータスチェック、セッションはクッキーにトークン店、イベントなどのためのハートビート

次のいずれかを実行できます。

  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、2015

2

angularjsでは、UIを表すUIパーツ、サービス、ディレクティブ、およびangularjsのすべてのパーツを作成できます。取り組むのは素晴らしい技術です。

このテクノロジーを初めて使用して「ユーザー」を認証したい人は、c#web apiの機能を使用して認証することをお勧めします。そのためには、ユーザーを認証するための強力なセキュリティメカニズムを構築するのに役立つOAuth仕様を使用できます。OAuthを使用してWebApiを作成したら、その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;
 
    };
 

トークンを取得したら、Tokenを使用してangularjsにリソースをリクエストし、OAuth仕様でWeb APIで安全に保持されているリソースにアクセスします。

詳細については、以下の記事をご覧ください。

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をキャッチしてブール値をTrueに変更するとどうなりますか?

このようなことをクライアント側に頼ってはいけません。ユーザーが認証されていない場合、サーバーはログイン/エラーページにリダイレクトするだけです。


2
これを確認してください:github.com/witoldsz/angular-http-auth-インターセプターはサーバーの応答ステータスコードをチェックし、それが403(「ログインが必要」)の場合はイベントをブロードキャストするため、アプリ内でキャッチしてログインボックスを表示できます。
aherok 2013年

10
回答を使用してお互いに返信するのをやめます。それがコメントの目的です!
2013年

@aherokの提案、あなたのコメントは回答に昇格する必要があります。それはすぐにトップに投票されます。残りはただのノイズです。
user237419 2014

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;
 
    };
 

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.