最近,我一直在使用AngularJS和Java EE6。我已经在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 Web服务器上部署了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; } }
这确实使我能够从AngularJS向玻璃鱼上部署的Java EE 6应用程序发送不同类型的HTTP请求。
问题是,当我从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;
但是,这并不能解决我的问题。我还尝试将它与config参数中的每个请求一起发送,但这也不能解决我的问题。
根据您使用的AngularJS版本,您可能必须在每个$ http上进行设置。
从1.2开始,您可以执行以下操作:
$http.get(url,{ withCredentials: true, ...})
从1.1.1起,您可以对其进行全局配置:
config(['$httpProvider', function($httpProvider) { $httpProvider.defaults.withCredentials = true; }]).
如果您使用的是Angular的旧版本,请尝试将配置对象传递给指定withCredentials的$ http。应该可以在1.1之前的版本中使用:
$http({withCredentials: true, ...}).get(...)
另请参阅mruelans答案和: