2013-08-18 6 views
14

RESTful API(Jersey)を使用するAngularJS Webアプリケーションを構築しています。AngularJSクライアントをサーバーに正しく認証する方法

私はJava Application Server(詳細はGlassfish 4)を使用しています。

次のように私のセットアップは次のとおりです。

  • AngularJS Webアプリケーションは、Java EEアプリケーションサーバへの単一のWARファイルとしてデプロイされます。
  • RESTfulAPI(およびバックエンドロジック)も、同じJava EEアプリケーションサーバーへのwarファイルとしてデプロイされます。
  • AngularJS Webアプリケーションは、必要なデータを取得するためにREST APIを呼び出します。
  • RESTfulなAPI:公共制限されていないアクセスのための
    • /api/public/*(例えば/ API /公共/ユーザー/サインアップは、新しいユーザーとして登録します)。どのユーザーもこのエリアにアクセスできます。いいえログインが
  • プライベートリソースは、Java EE内部セキュリティ概念で保護されているが(いくつかのアカウントを取得し、特定のデータに例えば/ API /プライベート/アカウント/ {ID})、アクセス制限のため
  • /api/private/*を必要としない(下記参照web.xmlの詳細については、

    <security-constraint> 
        <web-resource-collection> 
         <web-resource-name>PRIVATE REST API</web-resource-name> 
         <url-pattern>/private/*</url-pattern> 
         <http-method>GET</http-method> 
         <http-method>POST</http-method> 
         <http-method>HEAD</http-method> 
         <http-method>PUT</http-method> 
         <http-method>OPTIONS</http-method> 
         <http-method>TRACE</http-method> 
         <http-method>DELETE</http-method> 
        </web-resource-collection> 
        <auth-constraint> 
         <description>Have to be a USER</description> 
         <role-name>USERS</role-name> 
        </auth-constraint> 
    </security-constraint> 
    <login-config> 
        <auth-method>BASIC</auth-method> 
        <realm-name>userauth</realm-name> 
    </login-config> 
    <security-role> 
        <description/> 
        <role-name>USERS</role-name> 
    </security-role> 
    

    このセットアップ

web.xmlが、私は、ブラウザで手動でURLを呼び出す場合にのみ、しかし、私のために動作します。 私が認証されておらず、セキュリティで保護されたエリアをアドレス指定すると、ブラウザはユーザ名とパスワードを尋ねます。提供された資格情報が有効な場合、そこから私は制限されたエリアにアクセスできます。

しかし、どのようにAngularJSで動作させることができますか? POST API呼び出しがあります:/api/public/users/loginフォームから資格情報(ユーザー名とパスワード)を入力する必要があります。

クライアント側のコードは次のとおりです。

ctrls.controller('LoginController', function($scope, $http, $log, $location, UserService, RemoteServerHelperService) { 
    $scope.loginDataWrong = undefined; 
    $scope.login = function(credentials) { 
    $http.post(RemoteServerHelperService.buildURL('/public/users/login'), credentials) 
     .success(function (data, status) { 
      UserService.setLoggedIn(credentials.email); 
      $scope.loginDataWrong = undefined; 
      $location.path('/app'); 
      $log.info("login attempt: successfull. User.loggedIn:" + UserService.isLoggedIn()); 
     }).error(function (data, status, headers, config) { 
      UserService.invalidate(); 
      $scope.loginDataWrong = true; 
      $log.info("login attempt: failed. User.loggedIn:" + UserService.isLoggedIn()); 
     }); 
    }; 
}); 

クライアント側のコードが動作しているようです。クライアント側でコンテンツを保護するためのルートもいくつか用意されています。クライアントサイドコードを詳細に記述するいくつかの記事があります。だからこの "スニペット"で十分でしょう。

サーバー側のコードは次のとおりです。

@POST 
@Path("/login") 
@Consumes(MediaType.APPLICATION_JSON) 
public Response login(Credentials credentials, @Context HttpServletRequest request) { 
    if (isAlreadyAuthenticated(request)) { 
     try { 
      request.logout(); 
     } catch (ServletException ex) { 
      return Response.status(Status.CONFLICT).build(); 
     } 
    } 

    // not authenticated 
    try { 
     request.login(credentials.getEmail(), credentials.getPassword()); 
     return Response.ok().build(); 
    } catch (ServletException ex) { 
     return Response.status(Status.CONFLICT).build(); 
    } 
} 

しかし、しかし、これはさらに要求のためにクライアント側を「認証」しません。正常にログインした後、制限された領域でAPI呼び出しを行うと、サーバー側から403 FORBIDDENという応答が得られます。だから、私は何か間違っていると思います。さらなるリクエストのためにクライアントをサーバーに認証する方法はありますか?

可能な解決策は、FORMベースの認証に切り替えてj_usernameとj_passwordを使用してj_security_checkを呼び出すだけですが、今のところはBASIC認証に固執し、RESTful API経由で手動で認証を実行したいと考えています。

設定$httpProvider.defaults.withCredentials = true;は何らかの影響を与えていないようです。

更新:lossleaderの先端に

おかげで、私は問題を解決しました。 login()メソッドを削除しました。なぜなら、Java EE-Serverで認証をしたいからです。

保護領域にアクセスするには、AngularJS WebアプリケーションがHTTPヘッダーを正しく設定する必要があります。私の場合、$http.defaults.headers.common['Authorization'] = 'Basic <username:pw>';ここで、username:passwordはBase64でエンコードする必要があります。

ヘッダーを正しく設定すると、パスワードプロンプトが表示されず、AngularJS WebアプリケーションはREST APIにアクセスできます。

+1

request.authenticate()はレスポンスではっきりと働いていますが、request.login()はクライアントがhttp認証ヘッダーを取得する方法を知りません。したがってヘッダーを設定します。私は、認証を使用してブラウザに作業をさせたり、フォームを使用させたりします。間に本当に何かが必要な場合は、応答を見て、ヘッダーが設定されているかどうかを確認してください。 – lossleader

+1

あなたの返事に感謝します。もちろん、あなたは正しいです、私はヘッダーを正しく設定していないし、もちろん私の問題だった。あなたのヒントの後、私はBASICとフォームベースの認証で動作する認証を得ました。 – zip

答えて

5

ロスリーダーのおかげで、私はこの問題を解決しました。私は、Java EE-Serverに認証の世話をしたいので、login()メソッドを削除しました。

保護領域にアクセスするには、AngularJS WebアプリケーションがHTTPヘッダーを正しく設定する必要があります。私の場合、$ http.defaults.headers.common ['Authorization'] = 'Basic'; username:passwordはBase64でエンコードされている必要があります。

ヘッダーを正しく設定すると、パスワードプロンプトが表示されず、AngularJS WebアプリケーションはREST APIにアクセスできます。

+1

こんにちは、私はやや似たような質問をしました:http://stackoverflow.com/questions/24129848/how-to-integrate-angularjs-and-java-jaas-based-authentication - 実際にログインページを使用していますか?ログイン機構のためのフォーム?実際にログインした場所にコード部分を投稿し、その後にAPIを呼び出すと、ヘッダーにBase 64エンコーディングが設定されますか?私は安らぎのAPIのためのAngularJSリソースを使用していますあなたのアプローチでも動作しますか?ありがとう。 – guilhebl

関連する問題