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

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

问题描述

最近我一直在使用 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;

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

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,请尝试将配置对象传递给指定 withCredentials 的 $http.这应该适用于 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(...)

另见 mruelans 的回答和:

See also mruelans answer and:

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

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