web-dev-qa-db-ja.com

Web APIを使用したAngularJSクライアント側のルーティングとトークン認証

Asp.net mvc webapiをバックエンドおよびクライアント側ルーティング(cshtmlなし)として使用して、SPA angularjsアプリケーションで認証と承認の例を作成したいと思います。以下は、完全な例をセットアップするために使用できる関数の例です。しかし、私はそれをすべて一緒にすることはできません。任意の助けに感謝します。

質問:

  1. ベストプラクティスは何ですか:CookieまたはTokenベースですか?
  2. angularでベアラートークンを作成して、各リクエストで承認するにはどうすればよいですか?
  3. API関数の検証?
  4. クライアントでサインインしたユーザーを保持するにはどうすればよいですか?

サンプルコード:

  1. サインインフォーム

    <form name="form" novalidate>
     <input type="text" ng-model="user.userName" />
     <input type="password" ng-model="user.password" />
     <input type="submit" value="Sign In" data-ng-click="signin(user)">
    </form>
    
  2. 認証Angular Controller

    $scope.signin = function (user) {
    $http.post(uri + 'account/signin', user)
        .success(function (data, status, headers, config) {
            user.authenticated = true;
            $rootScope.user = user;
            $location.path('/');
        })
        .error(function (data, status, headers, config) {
    
            alert(JSON.stringify(data));
            user.authenticated = false;
            $rootScope.user = {};
        });
    };
    
  3. APIバックエンドAPIコード。

    [HttpPost]
    public HttpResponseMessage SignIn(UserDataModel user)
    {
        //FormsAuthetication is just an example. Can I use OWIN Context to create a session and cookies or should I just use tokens for authentication on each request? How do I preserve the autentication signed in user on the client?
        if (this.ModelState.IsValid)
        {
            if (true) //perform authentication against db etc.
            {
                var response = this.Request.CreateResponse(HttpStatusCode.Created, true);
                FormsAuthentication.SetAuthCookie(user.UserName, false);
    
                return response;
            }
    
            return this.Request.CreateErrorResponse(HttpStatusCode.Forbidden, "Invalid username or password");
        }
        return this.Request.CreateErrorResponse(HttpStatusCode.BadRequest, this.ModelState);
    }
    
  4. コンテンツを制限するためのJWTライブラリを使用した承認。

    config.MessageHandlers.Add(new JsonWebTokenValidationHandler
    {
      Audience = "123",
      SymmetricKey = "456"
    });
    
  5. 私のAPIメソッド

    [Authorize]
    public IEnumerable<string> Get()
    {
     return new string[] { "value1", "value2" };
    }
    
32

Cookie認証を使用するか(ベアラー)トークンを使用するかは、使用しているアプリの種類によって異なります。私の知る限り、まだベストプラクティスはありません。しかし、あなたはSPAに取り組んでおり、すでにJWTライブラリを使用しているので、トークンベースのアプローチを好むでしょう。

残念ながら、ASP.NETについてはサポートできませんが、通常、JWTライブラリはトークンを生成して検証します。必要なことは、資格情報(およびシークレット)でgenerateまたはencodeを呼び出し、すべての要求で送信されるトークンでverifyまたはdecodeを呼び出すだけです。また、サーバーに状態を保存したり、Cookieを送信したりする必要はありません。おそらくFormsAuthentication.SetAuthCookie(user.UserName, false)を使用して実行したことでしょう。

ライブラリが、トークンの生成/エンコードおよび検証/デコードの使用方法の例を提供していると確信しています。

したがって、生成と検証は、クライアント側で行うことではありません。

フローは次のようになります。

  1. クライアントは、ユーザーが提供したログイン資格情報をサーバーに送信します。
  2. サーバーは資格情報を認証し、生成されたトークンで応答します。
  3. クライアントはトークンをどこかに保存します(ローカルストレージ、Cookie、またはメモリのみ)。
  4. クライアントは、サーバーへのすべてのリクエストでトークンを認証ヘッダーとして送信します。
  5. サーバーはトークンを検証し、要求されたリソースを送信するか、401(または同様のもの)を送信してそれに応じて動作します。

ステップ1および3:

app.controller('UserController', function ($http, $window, $location) {
    $scope.signin = function(user) {
    $http.post(uri + 'account/signin', user)
        .success(function (data) {
            // Stores the token until the user closes the browser window.
            $window.sessionStorage.setItem('token', data.token);
            $location.path('/');
        })
        .error(function () {
            $window.sessionStorage.removeItem('token');
            // TODO: Show something like "Username or password invalid."
        });
    };
});

sessionStorageは、ユーザーがページを開いている限りデータを保持します。有効期限を自分で処理したい場合は、代わりにlocalStorageを使用できます。インターフェイスは同じです。

ステップ4:

サーバーへのすべての要求でトークンを送信するには、what Angular呼び出し インターセプター を使用できます。 )、すべての発信リクエストにヘッダーとして添付します。

app.factory('AuthInterceptor', function ($window, $q) {
    return {
        request: function(config) {
            config.headers = config.headers || {};
            if ($window.sessionStorage.getItem('token')) {
                config.headers.Authorization = 'Bearer ' + $window.sessionStorage.getItem('token');
            }
            return config || $q.when(config);
        },
        response: function(response) {
            if (response.status === 401) {
                // TODO: Redirect user to login page.
            }
            return response || $q.when(response);
        }
    };
});

// Register the previously created AuthInterceptor.
app.config(function ($httpProvider) {
    $httpProvider.interceptors.Push('AuthInterceptor');
});

そして常にSSLを使用するようにしてください!

91
bernhardw