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にアクセスできます。
request.authenticate()はレスポンスではっきりと働いていますが、request.login()はクライアントがhttp認証ヘッダーを取得する方法を知りません。したがってヘッダーを設定します。私は、認証を使用してブラウザに作業をさせたり、フォームを使用させたりします。間に本当に何かが必要な場合は、応答を見て、ヘッダーが設定されているかどうかを確認してください。 – lossleader
あなたの返事に感謝します。もちろん、あなたは正しいです、私はヘッダーを正しく設定していないし、もちろん私の問題だった。あなたのヒントの後、私はBASICとフォームベースの認証で動作する認証を得ました。 – zip