AngularJS与Jersey Webservice之间的通信,它们位于不同的域上.无法访问正确的会话

Wou*_*ter 13 xmlhttprequest jersey cors java-ee-6 angularjs

最近我一直在玩AngularJS和Java EE 6.我在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();
}
Run Code Online (Sandbox Code Playgroud)

这似乎工作正常,如果我从Postman发布/登录或从glassfish上部署的基本jQuery网页发送,我确实得到了正确的用户名并且已经放置了会话.如果我然后发送一个GET请求到/ ping我确实得到了我登录的用户名.

我在一个需要登录的node.js网络服务器上部署了一个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;
    }
}
Run Code Online (Sandbox Code Playgroud)

这确实使我可以将不同类型的HTTP请求从AngularJS发送到部署在glassfish上的Java EE 6应用程序.

问题是,当我从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);
            });
    };
};
Run Code Online (Sandbox Code Playgroud)

在另一个控制器:

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

我试过设置withCredentials是真的

$http.defaults.withCredentials = true;
Run Code Online (Sandbox Code Playgroud)

但这并没有解决我的问题.我也尝试用config参数中的每个请求发送它,但这也没有解决我的问题.

iwe*_*ein 20

根据您使用的AngularJS版本,您可能需要在每个$ http上设置它.

从1.2开始你可以做到:

$http.get(url,{ withCredentials: true, ...})
Run Code Online (Sandbox Code Playgroud)

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

config(['$httpProvider', function($httpProvider) {
  $httpProvider.defaults.withCredentials = true;
}]).
Run Code Online (Sandbox Code Playgroud)

如果您使用的是旧版本的Angular,请尝试将配置对象传递给指定withCredentials的$ http.这应该适用于1.1之前的版本:

$http({withCredentials: true, ...}).get(...)
Run Code Online (Sandbox Code Playgroud)

另见mruelans答案和:


sk8*_* ツ 6

只是对@iwein anwser的更新,我们现在可以在配置中设置

config(['$httpProvider', function($httpProvider) {
  $httpProvider.defaults.withCredentials = true;
}]).
Run Code Online (Sandbox Code Playgroud)

https://github.com/angular/angular.js/pull/1209

(仅在不稳定版本之后可用:1.1.1)


mru*_*lan 5

在1.2版本中,这对我不起作用:

$http({withCredentials: true, ...}).get(...) 
Run Code Online (Sandbox Code Playgroud)

如果我读了doc,快捷方法应该采用config对象

$http.get(url,{ withCredentials: true, ...})
Run Code Online (Sandbox Code Playgroud)

$ http是一个单例,这是混合使用和不使用凭据的相同应用程序请求的唯一方法.