2013-08-18 2 views
14

Я создаю веб-приложение AngularJS, которое использует API RESTful (Джерси).Как правильно аутентифицировать клиента AngularJS на сервере

На стороне сервера я использую сервер приложений Java (подробно Glassfish 4).

Моя установка выглядит следующим образом:

  • AngularJS WebApp развернут в качестве единого военного файла на сервер Java EE приложений.
  • RESTfulAPI (и внутренняя логика) также развертывается в качестве военного файла на том же сервере приложений Java EE.
  • Приложение AngularJS webapp вызывает API REST для получения необходимых ему данных.
  • RESTful API:
    • /api/public/* для общественности не ограниченного доступа (например,/API/общественности/пользователей/регистрации для регистрации в качестве нового пользователя). Любой пользователь имеет доступ к этой области. Нет Войти не требуется
    • /api/private/* для ограниченного доступа (например,/апи/частный/счет/{ID}, чтобы получить какой-то счет конкретных данных)
  • Частные ресурсы защищены с понятиями внутренней безопасности Java EE (см для деталей web.xml).

web.xml

<security-constraint> 
    <web-resource-collection> 
     <web-resource-name>PRIVATE REST API</web-resource-name> 
     <url-pattern>/private/*</url-pattern> 
     <http-method>GET</http-method> 
     <http-method>POST</http-method> 
     <http-method>HEAD</http-method> 
     <http-method>PUT</http-method> 
     <http-method>OPTIONS</http-method> 
     <http-method>TRACE</http-method> 
     <http-method>DELETE</http-method> 
    </web-resource-collection> 
    <auth-constraint> 
     <description>Have to be a USER</description> 
     <role-name>USERS</role-name> 
    </auth-constraint> 
</security-constraint> 
<login-config> 
    <auth-method>BASIC</auth-method> 
    <realm-name>userauth</realm-name> 
</login-config> 
<security-role> 
    <description/> 
    <role-name>USERS</role-name> 
</security-role> 

Эта установка работает для меня, но только если я призываю URL-адреса вручную в браузере. Если я не аутентифицирован и не адресую защищенную зону, браузер запрашивает имя пользователя и пароль. Если предоставленные полномочия действительны, я оттуда имею доступ к запрещенной зоне: Хорошо.

Но как мне получить эту работу с AngularJS? Для входа в систему есть вызов POST API: /api/public/users/login, где вы должны предоставить учетные данные из формы (имя пользователя и пароль).

сторона код клиента:

ctrls.controller('LoginController', function($scope, $http, $log, $location, UserService, RemoteServerHelperService) { 
    $scope.loginDataWrong = undefined; 
    $scope.login = function(credentials) { 
    $http.post(RemoteServerHelperService.buildURL('/public/users/login'), credentials) 
     .success(function (data, status) { 
      UserService.setLoggedIn(credentials.email); 
      $scope.loginDataWrong = undefined; 
      $location.path('/app'); 
      $log.info("login attempt: successfull. User.loggedIn:" + UserService.isLoggedIn()); 
     }).error(function (data, status, headers, config) { 
      UserService.invalidate(); 
      $scope.loginDataWrong = true; 
      $log.info("login attempt: failed. User.loggedIn:" + UserService.isLoggedIn()); 
     }); 
    }; 
}); 

Клиентская часть кода, кажется, работает. У меня также есть несколько путей для защиты контента на стороне клиента и т. Д. Есть несколько сообщений, которые подробно описывают код на стороне клиента. Поэтому этого «фрагмента» должно быть достаточно.

сторона код сервера:

@POST 
@Path("/login") 
@Consumes(MediaType.APPLICATION_JSON) 
public Response login(Credentials credentials, @Context HttpServletRequest request) { 
    if (isAlreadyAuthenticated(request)) { 
     try { 
      request.logout(); 
     } catch (ServletException ex) { 
      return Response.status(Status.CONFLICT).build(); 
     } 
    } 

    // not authenticated 
    try { 
     request.login(credentials.getEmail(), credentials.getPassword()); 
     return Response.ok().build(); 
    } catch (ServletException ex) { 
     return Response.status(Status.CONFLICT).build(); 
    } 
} 

Но тем не менее, это не «аутентификации» на стороне клиента для дальнейших запросов. Когда я делаю вызов API в ограниченной области после успешного входа в систему, я получаю ответ от со стороны сервера. Поэтому я предполагаю, что я делаю что-то неправильно. Есть ли у вас какие-либо идеи по аутентификации клиента на сервере для дальнейших запросов?

Возможное решение может заключаться в том, чтобы переключиться на аутентификацию на основе FORM и просто вызвать j_security_check с j_username и j_password, но на данный момент я хочу придерживаться BASIC-аутентификации и выполнять аутентификацию вручную через RESTful API.

Настройка $httpProvider.defaults.withCredentials = true; как-то не имеет никакого эффекта.

Update:

Благодаря кончике lossleader я решил проблему. Я удалил метод login(), потому что я хочу, чтобы Java EE-Server выполнял проверку подлинности.

Для доступа к защищенным областям веб-приложение AngularJS должно правильно установить HTTP-заголовок. В моем случае $http.defaults.headers.common['Authorization'] = 'Basic <username:pw>';, где username:password должен быть закодирован Base64.

После того, как я правильно установил заголовки, не отображается «Запрос пароля», и веб-приложение AngularJS может получить доступ к API REST.

+1

Я не вижу, как запрос request.login() приведет к тому, что клиент получит HTTP-заголовки auth (правда, только ваш 200 возвращается?), В то время как request.authenticate() довольно четко работает с ответом и может поэтому установите заголовки. Я либо использовал бы аутентификацию, либо позволял браузеру выполнять свою работу или использовать формы. Если вы действительно хотите что-то посреди, я думаю, вам лучше посмотреть ответ и посмотреть, установлены ли какие-либо заголовки. – lossleader

+1

Эй, спасибо, благодарю за ваш ответ. Конечно, вы правы, я не задавал заголовки правильно, и это, конечно, было моей проблемой. После вашего намека я получил аутентификацию для работы с аутентификацией на базе BASIC и FORM. – zip

ответ

5

Благодаря подсказке lossleader я решил проблему. Я удалил метод login(), потому что я хочу, чтобы Java EE-Server выполнял проверку подлинности.

Для доступа к защищенным областям веб-приложение AngularJS должно правильно установить HTTP-заголовок. В моем случае $ http.defaults.headers.common ['Authorization'] = 'Basic'; где username: пароль должен быть закодирован Base64.

После того, как я правильно установил заголовки, не отображается «Запрос пароля», и веб-приложение AngularJS может получить доступ к API REST.

+1

Привет, я задал несколько схожий вопрос: http://stackoverflow.com/questions/24129848/how-to-integrate-angularjs-and-java-jaas-based-authentication - вы фактически используете страницу входа с форма для механизма входа? Можете ли вы опубликовать фрагмент кода, в котором вы действительно заходите, а для последующих вызовов API вы заполняете заголовок кодировкой Base 64? Я использую AngularJS Resource for Restful API, который также будет работать с вашим подходом? Благодарю. – guilhebl