AngularJS 和位于不同域上的 Jersey Web 服务之间的通信.无法访问正确的会话 [英] Communication between AngularJS and a Jersey Webservice which are on a different domain. Can't access correct session

查看:12
本文介绍了AngularJS 和位于不同域上的 Jersey Web 服务之间的通信.无法访问正确的会话的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

最近我一直在玩 AngularJS 和 Java EE 6.我用 Jersey 构建了一个 web 服务,并在 Glassfish 上部署了该项目.因为我需要某种身份验证和 OAuth 实现或 JDBCRealm 似乎有点矫枉过正,所以我决定如果用户成功登录就创建一个会话.

Lately I've been playing around with AngularJS and Java EE 6. I've build an webservice with Jersey and deployed the project on Glassfish. Because I needed some kind of authentication and an OAuth implementation or an JDBCRealm seemed overkill I decided to just create a session if the user successfully logged in.

@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 请求,我确实会取回我登录的用户名.

This seems to work alright, if I post to /login from Postman or from a basic jQuery webpage deployed on glassfish I do get the correct username back and a session has been placed. If I then send a GET request to /ping I do get the username back from which I logged in.

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

I've an AngularJS application deployed on a node.js webserver which needed to login. Because this server is on another port its on another domain and I had to go through the pain of enabling cors. I did this by building a container response filter which sets the response headers.

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;
    }
}

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

This did made it possible for me to send different types of HTTP requests from AngularJS to Java EE 6 application deployed on glassfish.

问题是,当我从 AngularJS 向/login 方法发送 POST 请求时,会创建一个会话并且我确实取回了我的用户名.但是当我向/ping 方法发送 GET 请求时,我收到没有设置用户名属性的会话"通知.

The problem is that when I send a POST request from AngularJS to the /login method, a session is created and I do get my username back. But when I send a GET request to the /ping method I get the "no session with an username attribute has been set" notice.

我相信这与跨域预防有关,并且我必须在发送 xhr 请求时设置 withCredentials 标记.我一直在尝试在 AngularJS 中做到这一点,但还没有找到如何做到这一点.

I believe this has to do with cross domain prevention and that I've to set the withCredentials tag when I send a xhr request. I've been trying to do this in AngularJS but haven't found out how to do this.

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

I've tried to set withCredentials is true

$http.defaults.withCredentials = true;

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

This however didn't solve my problem. I also tried to send it with every request in the config parameter but this didn't solve my problem either.

推荐答案

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

Depending on the version of AngularJS you are using you might have to set it on each $http.

从 1.2 开始,您可以:

Since 1.2 you can do:

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

从 1.1.1 开始,您可以全局配置它:

From 1.1.1 you can globally configure it:

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

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

If you're using an older version of Angular, try passing a config object to $http that specifies withCredentials. That should work in versions before 1.1:

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

另见 mruels 的回答和:

See also mruelans answer and:

这篇关于AngularJS 和位于不同域上的 Jersey Web 服务之间的通信.无法访问正确的会话的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆