一尘不染

AngularJS和位于另一个域的Jersey Webservice之间的通信。无法访问正确的会话

angularjs

最近,我一直在使用AngularJS和Java
EE6。我已经在Jersey上构建了一个Web服务,并在Glassfish上部署了该项目。因为我需要某种身份验证,并且需要OAuth实现或JDBCRealm,所以我决定仅在用户成功登录后才创建会话。

@POST
@Path("/login")
@Produces({MediaType.APPLICATION_JSON})
@Consumes({MediaType.APPLICATION_JSON})
public Response login(LoginDAO loginData, @Context HttpServletRequest req) {
    req.getSession().invalidate();
    loginData.setPassword(PasswordGenerator.hash(loginData.getPassword()));
    User foundUser = database.login(loginData);
    if(foundUser == null) {
        return Response.status(Status.CONFLICT).build();
    }
    req.getSession(true).setAttribute("username", foundUser.getUsername());
    return Response.ok().build();
}

@GET
@Path("/ping")
public Response ping(@Context HttpServletRequest req) {
    if(req.getSession().getAttribute("username") == null) {
        return Response.ok("no session with an username attribute has been set").build();
    }
    return Response.ok(req.getSession(true).getAttribute("username")).build();
}

如果我从Postman或从glassfish上部署的基本jQuery网页发布到/
login,这似乎还可以,我确实获得了正确的用户名,并且已经建立了会话。然后,如果我向/ ping发送GET请求,则确实会获得我登录时使用的用户名。

我已经在需要登录的node.js
Web服务器上部署了AngularJS应用程序。因为该服务器位于另一个域上的另一个端口上,所以我不得不经历启用cors的痛苦。我通过构建一个设置响应头的容器响应过滤器来做到这一点。

public class CrossOriginResourceSharingFilter implements ContainerResponseFilter {
    @Override
    public ContainerResponse filter(ContainerRequest creq, ContainerResponse cresp) {
        cresp.getHttpHeaders().putSingle("Access-Control-Allow-Origin", "http://localhost:8000");
        cresp.getHttpHeaders().putSingle("Access-Control-Allow-Credentials", "true");
        cresp.getHttpHeaders().putSingle("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
        cresp.getHttpHeaders().putSingle("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With");
        return cresp;
    }
}

这确实使我能够从AngularJS向玻璃鱼上部署的Java EE 6应用程序发送不同类型的HTTP请求。

问题是,当我从AngularJS向/ login方法发送POST请求时,创建了一个会话,并且确实获得了我的用户名。但是,当我向/
ping方法发送GET请求时,收到“未设置用户名属性的会话”通知。

我认为这与跨域防护有关,并且在发送xhr请求时必须设置withCredentials标记。我一直在尝试在AngularJS中执行此操作,但尚未找到如何执行此操作。

function LoginCtrl($scope, $http) {
    $scope.login = function() {
        $http.post("glassfish:otherport/api/login", $scope.credentials).
            success(function(data) {
                console.log(data);
            }).
            error(function(data, error) {
                console.log(error);
            });
    };
};

在另一个控制器中:

$scope.getUsername = function() {
    $http.get("glassfish:otherport/api/ping", {}).
        success(function(data) {
            $scope.username = data;
        }).
        error(function() {
            $scope.username = "error";
        })
    }

我试图将withCredentials设置为true

$http.defaults.withCredentials = true;

但是,这并不能解决我的问题。我还尝试将它与config参数中的每个请求一起发送,但这也不能解决我的问题。


阅读 209

收藏
2020-07-04

共1个答案

一尘不染

根据您使用的AngularJS版本,您可能必须在每个$ http上进行设置。

从1.2开始,您可以执行以下操作:

$http.get(url,{ withCredentials: true, ...})

从1.1.1起,您可以对其进行全局配置:

config(['$httpProvider', function($httpProvider) {
  $httpProvider.defaults.withCredentials = true;
}]).

如果您使用的是Angular的旧版本,请尝试将配置对象传递给指定withCredentials的$ http。应该可以在1.1之前的版本中使用:

$http({withCredentials: true, ...}).get(...)

另请参阅mruelans答案和:

2020-07-04