如何正确地向服务器验证AngularJS客户端

时间:2013-08-18 14:36:13

标签: java java-ee authentication angularjs

我正在构建一个使用RESTful API(Jersey)的AngularJS网络应用程序。

在服务器端,我使用的是Java Application Server(详见Glassfish 4)。

我的设置如下:

  • AngularJS webapp作为单个war文件部署到Java EE Application服务器。
  • RESTfulAPI(和后端逻辑)也作为war文件部署到同一个Java EE应用服务器。
  • AngularJS webapp调用REST API以获取所需的数据。
  • RESTful API:
    • /api/public/*用于公共访问限制(例如/ api / public / users / signup注册为新用户)。允许任何用户访问此区域。无需登录
    • /api/private/*限制访问(例如/ api / private / account / {id}检索某些帐户特定数据)
  • 私有资源受Java EE内部安全性概念的保护(有关web.xml的详细信息,请参阅下文)。

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>

此设置适用于我,但仅限于我在浏览器中手动调用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-Authentication并通过RESTful API手动执行身份验证。

设置$httpProvider.defaults.withCredentials = true;似乎没有任何影响。

更新

感谢失误领导者,我解决了这个问题。 我删除了login()方法,因为我希望Java EE-Server能够处理身份验证。

要访问安全区域,AngularJS webapp必须正确设置HTTP-Header。在我的情况$http.defaults.headers.common['Authorization'] = 'Basic <username:pw>';中,其中username:password必须是Base64编码的。

正确设置标头后,没有显示密码提示,AngularJS webapp可以访问REST API。

1 个答案:

答案 0 :(得分:5)

感谢失误领导者,我解决了这个问题。我删除了login()方法,因为我希望Java EE-Server能够处理身份验证。

要访问安全区域,AngularJS webapp必须正确设置HTTP-Header。在我的情况下$ http.defaults.headers.common ['授权'] ='基本';其中username:password必须是Base64编码。

正确设置标头后,没有显示密码提示,AngularJS webapp可以访问REST API。