AngularJS和泽西网络服务之间的通信,它们位于不同的领域。不能访问正确的会话吗

时间:2022-07-02 19:35:38

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.

最近我一直在玩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();
}

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.

这似乎没问题,如果我从Postman或在glassfish上部署的jQuery基础页面上发布/登录,我就会得到正确的用户名,并且已经设置了会话。如果我发送一个GET请求到/ping,我就会得到我登录的用户名。

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.

我在节点上部署了一个AngularJS应用程序。需要登录的js webserver。因为这个服务器在另一个端口上它在另一个域上,我不得不经历启用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;
    }
}

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

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

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.

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

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.

我认为这与跨域预防有关,我必须在发送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);
            });
    };
};

And in another controller:

而在另一个控制器:

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

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.

但这并不能解决我的问题。我还尝试在配置参数中的每个请求中发送它,但这也没有解决我的问题。

3 个解决方案

#1


19  

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

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

Since 1.2 you can do:

1.2你可以做到:

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

From 1.1.1 you can globally configure it:

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

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

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,它指定了凭据。在1.1之前的版本中应该有效:

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

See also mruelans answer and:

参见mruelans的回答:

#2


5  

just an update to @iwein anwser, that we can now set in config itself

只是更新到@iwein anwser,我们现在可以设置它自己了。

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

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

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

(available only after unstable version: 1.1.1)

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

#3


5  

In 1.2 version, this doesn't work for me:

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

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

if I read the doc, the shortcut method should take the config object

如果我读取文档,快捷方法应该使用配置对象。

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

$http is a singleton, That's the only way to mix in a same application requests with and without credentials.

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

#1


19  

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

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

Since 1.2 you can do:

1.2你可以做到:

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

From 1.1.1 you can globally configure it:

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

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

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,它指定了凭据。在1.1之前的版本中应该有效:

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

See also mruelans answer and:

参见mruelans的回答:

#2


5  

just an update to @iwein anwser, that we can now set in config itself

只是更新到@iwein anwser,我们现在可以设置它自己了。

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

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

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

(available only after unstable version: 1.1.1)

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

#3


5  

In 1.2 version, this doesn't work for me:

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

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

if I read the doc, the shortcut method should take the config object

如果我读取文档,快捷方法应该使用配置对象。

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

$http is a singleton, That's the only way to mix in a same application requests with and without credentials.

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