最近我一直在玩 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();
}
这似乎工作正常,如果我从 Postman 或从部署在 glassfish 上的基本 jQuery 网页发布到 /login,我确实会得到正确的用户名并且已经放置了一个会话。如果我随后向 /ping 发送 GET 请求,我确实会取回我登录时使用的用户名。
我在需要登录的 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;
}
}
这确实使我能够将不同类型的 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);
});
};
};
在另一个控制器中:
$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;
然而,这并没有解决我的问题。我还尝试将它与配置参数中的每个请求一起发送,但这也没有解决我的问题。