Связь между AngularJS и веб-сервисом Джерси, которые находятся в другом домене. Не удается получить доступ к правильному сеансу
В последнее время я играю с AngularJS и Java EE 6. Я создал веб-сервис на Джерси и развернул проект на 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 или с базовой веб-страницы jQuery, развернутой на glassfish, я получаю верное имя пользователя, и сеанс размещается. Если я затем отправляю запрос GET в /ping, я получаю имя пользователя, с которого я вошел.
У меня есть приложение AngularJS, развернутое на веб-сервере node.js, которое необходимо для входа. Потому что этот сервер находится на другом порту, а на другом домене, и мне пришлось пройти через боль включения мозгов. Я сделал это путем создания фильтра ответа контейнера, который устанавливает заголовки ответа.
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 в приложение Java EE 6, развернутое на glassfish.
Проблема в том, что когда я отправляю запрос POST от AngularJS методу /login, создается сеанс, и я получаю свое имя пользователя обратно. Но когда я отправляю запрос GET методу /ping, я получаю уведомление "сессия не установлена с атрибутом имени пользователя".
Я считаю, что это связано с междоменной профилактикой и что мне нужно установить тег withCredentials при отправке запроса xhr. Я пытался сделать это в 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 это правда
$http.defaults.withCredentials = true;
Это, однако, не решило мою проблему. Я также пытался отправить его с каждым запросом в параметре config, но это тоже не решило мою проблему.
3 ответа
В зависимости от версии AngularJS, которую вы используете, вам может потребоваться установить ее для каждого $http.
С версии 1.2 вы можете сделать:
$http.get(url,{ withCredentials: true, ...})
Начиная с версии 1.1.1 вы можете настроить его глобально:
config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.withCredentials = true;
}]).
Если вы используете более старую версию Angular, попробуйте передать объект конфигурации в $http, который указывает withCredentials. Это должно работать в версиях до 1.1:
$http({withCredentials: true, ...}).get(...)
См. Также ответ мрюеланов и:
Просто обновление @iwein anwser, которое мы теперь можем установить в самом конфиге
config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.withCredentials = true;
}]).
https://github.com/angular/angular.js/pull/1209
(доступно только после нестабильной версии: 1.1.1)
В версии 1.2 это не работает для меня:
$http({withCredentials: true, ...}).get(...)
если я прочитал документ, метод ярлыка должен взять объект конфигурации
$http.get(url,{ withCredentials: true, ...})
$http - это одиночный файл. Это единственный способ смешивать запросы одного и того же приложения с учетными данными и без них.