Как сделать сервис java

Добавил пользователь Алексей Ф.
Обновлено: 04.10.2024

Существует множество способов создать RESTful веб-сервис. Но использование Spring Framework обладает некоторыми преимуществами. Этот фреймворк предоставляет предварительно настроенные компоненты, внедрение зависимости и инверсию управления (IoC). Что особенно востребовано при создании RESTful веб-сервисов.

Что такое REST?

Общие принципы Spring и REST

Spring обладает преимуществами, которые упрощают создание сложных RESTful веб-сервисов. REST – это стиль архитектуры, который удобен для разработки веб-приложений.

Spring framework упрощает разработку приложений со слабой связностью. Он позволяет создавать веб-сервисы с использованием любых компонентов фреймворка и в будущем заменять их на другие.

Преимущества REST в Spring Framework

В то время как разработчик работает над созданием программы, фреймворк берёт на себя реализацию API транзакций, API JMX, API JMS и т.д. Spring framework может быть использован для реализации решений на базе Java Enterprise (JEE) и других стандартов.

Главные преимущества Spring framework:

Подход ModelAndView – хорошо документирован. Он позволяет соединить модель REST с моделью MVC.

Настройка среды

Чтобы создать RESTful веб-сервис с помощью Spring framework, нам потребуются следующие ресурсы:

  • JDK версии 1.8 или выше.
  • Maven 3.0 + .
  • Eclipse IDE или любая другая среда разработки.
  • Spring framework.

Пример приложения

В этом примере приложения для сборки проекта используется Maven. Мы проверим каждый компонент, который потребуется для приложения.
Сначала рассмотрим файл pom.xml, чтобы определить основные понятия и их иерархию.

Листинг 1 : – пример файла конфигурации pom.xml

Этот файл содержит все зависимости и плагины, необходимые для процесса сборки Maven.

Листинг 2 : – пример файла ресурсов

Рассмотрим файл ресурсов. Это будет старый добрый Java-класс с конструктором и акцессорами.

При выполнении этого кода контроллера программа выводит переданные значения.

Заключение

В этой статье мы рассмотрели особенности создания RESTful веб-сервисов в Spring framework. Мы также рассмотрели примеры реализации низкоуровневых компонентов.

Дайте знать, что вы думаете по данной теме материала в комментариях. Мы очень благодарим вас за ваши комментарии, лайки, дизлайки, подписки, отклики!

Пожалуйста, оставляйте свои отзывы по текущей теме статьи. За комментарии, подписки, дизлайки, отклики, лайки огромное вам спасибо!

Когда вы взаимодействуете с любой веб-страницей, это включает запрос и ответ через HTML-страницу. Аналогично, веб-сервисы также включают запрос и ответ, но в форме XML или JSON. Java, являясь подходящим языком для взаимодействия на стороне сервера, обеспечивает взаимодействие между различными приложениями на разных платформах.

Что такое веб-сервис в Java?

Веб-сервис в Java является подходящей средой для распространения связи между клиентскими и серверными приложениями во всемирной паутине. Это программный модуль, который предназначен для выполнения определенного набора задач следующим образом:

  • Веб-сервисы можно искать по сети, а также вызывать их соответствующим образом.
  • При вызове веб-сервис сможет предоставить функциональность клиенту, который вызывает этот веб-сервис.

Преимущества

Как правило, существует два типа веб-сервисов в Java:

  1. Soap Web Services.
  2. RESTful Web Services

1. Soap

Веб-сервис Soap

На приведенном выше рисунке вы можете заметить, как клиент будет общаться с поставщиком услуг. Поэтому для связи клиент должен знать такую информацию, как расположение сервера веб-служб, доступные функции, типы подписи и возврата, а также форматы ввода-вывода.

Поставщик услуг создаст стандартный XML-файл, который будет содержать всю вышеуказанную информацию. Таким образом, если этот файл передан клиенту, он сможет получить доступ к веб-сервису.

2. RESTful

Передача состояния представления (REST) – это клиент-серверная архитектура без сохранения состояния, в которой веб-службы рассматриваются как ресурсы и могут быть идентифицированы по их URL-адресам. Он состоит из двух компонентов REST-сервера, который обеспечивает доступ к ресурсам, и REST-клиента, который получает доступ и изменяет ресурсы REST. Взгляните на рисунок ниже для того же.

RESTful

Существует два основных API, определенных для разработки приложений веб-служб.

  1. JAX-WS: в основном для веб-сервисов SOAP. Существует два способа написания кода приложения JAX-WS: по стилю RPC и стилю документа.
  2. JAX-RS: в основном для веб-сервисов RESTful. В настоящее время для создания приложения JAX-RS используется в основном две реализации: Jersey и RESTeasy.

Оба эти API-интерфейса Java являются частью стандартной установки JDK, поэтому вам не нужно добавлять какие-либо jar-файлы для работы с ними.

Пример JAX-WS

Пример JAX-RS

Джерси является эталонной реализацией API JAX-RS, он не является частью стандартного JDK, и вы должны включить все необходимые банки. Лучший способ – использовать сборку Maven, поэтому создайте простой веб-проект Dynamic, а затем преобразуйте его в Maven в Eclipse.

Чтобы создать приложение JAX-RS, вам необходимо выполнить следующие шаги.

Шаг 1: Добавьте зависимости в файл pom.xml, как показано ниже:

Шаг 2: Теперь следующим шагом является добавление сервлета Jersey в наш дескриптор развертывания web.xml в качестве фронт-контроллера.

Шаг 3: После всего этого давайте теперь создадим простой класс обслуживания JAX-RS.

После настройки вышеуказанного файла вам просто нужно экспортировать его как файл WAR, а затем получить к нему доступ в браузере. Вы получите вывод, как показано ниже.

По просьбе камрада Gangsta раскрываю подробности работы NSIS-скрипта, описанного в прошлом топике. В нем было перечислено несколько файлов, входящих в тестовый дистрибутив (install.bat, wrapper.properties) и т.п. Что в них находится и зачем они нужны? С точки зрения изучения возможностей установщика NSIS эта информация избыточна: файлы и файлы, которые могли называться как угодно и содержать что угодно. Главное было — положить их в нужную папку на целевой машине. В отладочных целях в том скрипте не был предусмотрен даже автозапуск самопального install.bat (хотя возможности для этого в NSIS есть).

Однако рассмотренный пример интересен еще и тем, что устанавливает на Windows-компьютер Java-приложение в качестве сервиса, а это весьма ценно. Ведь сервис запускается скрытым для обычного пользователя образом (т.е. на экране не маячит дурацкое черное окно), может выполнять привилегированные операции, его можно перезапускать и останавливать. Как всё это реализовать, если речь идет о Java-приложении (в данном случае — Apache Felix)?

Вообще-то, на затронутую тему я уже писал на Мтааламу. Однако было это в самом начале жизни сайта и материал почти никто не заметил (судя по его рейтингу и количеству комментариев). Да и сам топик был беглый: есть, мол такой проект — Java Service Wrapper, посвященный именно запуску Java приложений в качестве сервисов, причем как под Windows, так и под *NIX. Хорошо, что спустя год появился повод вернуться вернуться к этой теме.

Если вы скачаете дистрибутив Java Service Wrapper, то обнаружите там множество файлов на все случаи жизни: для разных версий Windows и Linux. Из них для запуска сервиса на обычной Windows-XP нужны только три:

* wrapper-windows-x86-32.exe
* wrapper-windows-x86-32.dll
* wrapper.jar

плюс конфигурационный файл, настроив который, вы можете запускать любое консольное Java-приложение, имеющее метод public static void main(String[] args) в виде сервиса. В зависимости от ключей, сервис может быть:

запущен в консольном режиме в целях отладки (без установки в качестве сервиса):

Осталось рассмотреть конфигурационный файл. В случае с Apache Felix он выглядит так:

По-моему, особые комментарии не требуются. Скажу лишь, что поскольку файл содержит кириллические буквы, желательно сохранить его в кодировке Cp1251, иначе его название в списке сервисов Windows будет крокозябрами. А о том, что всё это работает и сервис действительно появляется в списке, свидетельствует скриншот из старого топика:

В прошлой статье, мы спроектировали и реализовали простой сервис BookStore.

В этой части мы попытаемся добавить безопасности в наше приложение — сделаем отдельный микросервис аутентификации/авторизации, а в нашем приложении BookStore запретим вызов методов неавторизованными пользователями. И хотя существуют готовые решения (например, Spring Security), мы напишем всё сами, чтобы разобрать принципы работы.

Как можно решить эту задачу? Сервис авторизации может открывать сессию пользователя, выдавая ему идентификатор сессии. С этим идентификатором пользователь может обращаться к требуемому сервису, передавая в параметрах запроса (или в заголовке) идентификатор сессии. Далее сервис, получив этот идентификатор может обратиться к сервису авторизации и проверить, действительно ли такая сессия открыта и можно ли предоставить пользователю доступ к ресурсу.


Сейчас у нас всего один сервис, которому требуется авторизация. Но в реальности таких сервисов может быть очень много. И при такой архитектуре нагрузка на сервис авторизации будет расти лавинообразно. Поэтому хорошо бы авторизовать пользователя однократно, выдав ему что-то, что может приниматься всеми другими системами без валидации на стороне авторизационного сервиса. Для таких целей можно воспользоваться JWT.

JWT (JSON Web Tokens)

JWT — это стандарт, основанный на JSON, для создания токенов доступа. Он состоит из трех частей: заголовка, тела и подписи:


В заголовке указывается тип токена и алгоритм подписи:

В тело записывается необходимая пользовательская информация (payload). Для аутентификации и авторизации это может быть id пользователя, его роль, время действия токена:

  • sub — уникальный идентификатор пользователя (subject)
  • iat — время выпуска токена в unix-time формате (issued at)
  • exp — время действия токена (expiration time). Также в unix-time формате. После окончания действия токена он не должен приниматься вызываемой стороной

Для того чтобы токен выглядел компактно заголовок и тело кодируются алгоритмом Base64-URL, разделяются точками и в конце добавляется подпись.

27–29 января, Онлайн, Беcплатно

Основная идея JWT заключается в том, что подписанный токен нельзя подделать, т.к. любое изменение тела или заголовка приведет к невалидности подписи. Секретный ключ, которым подписывается токен, хранится в тайне на сервере. Принимающая токен сторона, зная секретный ключ, может с легкостью проверить подпись — взять тело и заголовок, вычислить HS256 и сравнить с присланным. Если они совпадают, то токен не модифицировался и можно доверять ему содержимому. Это позволяет реализовать следующую архитектуру нашей системы:


Пользователь делает запрос на авторизационный сервис, передавая свои аутентификационные данные (например, логин и пароль), а сервис формирует токен в виде JWT, в котором будет указан id пользователя и его права. Права определяют к каким данным, сервисам он будет иметь доступ. Если это администратор системы, то он может иметь больше прав, чем обычный пользователь.

Получив токен, пользователь будет использовать его при вызове других сервисов. Каждому сервису необходимо дать секретный ключ, с помощью которого он может проверить валидность токена и разрешить пользователю выполнять запрошенные действия. И для этого не потребуется каждый раз вызывать авторизационный сервис.

Когда время действия токена подойдет к концу, вызываемый сервис ответит ошибкой, которая будет указывать на необходимость повторно получить токен на сервисе авторизации.

Для того чтобы пользователь не вводил каждый раз логин и пароль, когда токен заканчивает свое действие, обычно при авторизации выписываются сразу два токена: access token и refresh token. Первый имеет короткий срок жизни и используется для доступа к ресурсам (скажем 5 минут), а второй более длинный (например неделю, месяц). Как только access token заканчивает свое действие, пользователь делает запрос на авторизационный сервис с refresh token, получая в ответ обновленные оба токена. Если пользователь был неактивен длительное время (больше чем срок действия refresh token), то ему придется заново аутентифицироваться, введя свой логин и пароль.

Бывают случаи, когда необходимо отозвать выданные токены. Это может потребоваться, когда токены скомпрометированы или когда пользователь хочет выйти из своего аккаунта на всех устройствах, где он уже входил и получил токены. Такая задача решается использованием черного списка, который хранится на сервере (например, в БД). Отозванные токены будут храниться в нем до истечения срока жизни. Объем такой базы будет намного меньше, чем БД с пользователями.

Auth-сервис

Перейдем от теории к практике и напишем простой сервис, который будет аутентифицировать пользователя и выдавать ему токен доступа. Шаги по созданию проекта ничем не отличаются от предыдущей части, поэтому я их опущу.

Пользователи будут храниться в БД. В идеале это должна быть отдельная БД, но в обучающих целях будем использовать ту же, что использовали в первой части. Опишем DAO пользователя:

Репозиторий будет выглядеть совсем просто:

Т.к. мы будем реализовывать Client Credentials Flow в терминах протокола OAuth, то здесь client — это и есть пользователь. Соответственно clientId, clientSecret — аутентификационные данные пользователя. В открытом виде пароль пользователя хранить нельзя, поэтому будем хранить некий хеш, о котором будет написано ниже.

Опишем сервис, который будет регистрировать нового клиента и проверять его аутентификационные данные:

Для правильного хранения паролей в БД будем использовать Bcrypt. Это криптографическая хеш-функция, основанная на шифре Blowfish. Воспользуемся реализацией в библиотеке jBCrypt, добавим зависимость в проект:

Реализуем интерфейс ClientService :

При регистрации клиента мы генерируем соль вызовом метода BCrypt.gensalt() и используем её для вычисления хеша. В результате получаем строку, содержащую соль и хеш пароля. Полученное значение сохраняем в БД. Пример сгенерированного хеша:

  • $2a$10$ — заголовок (алгоритм bcrypt и количество раундов хеширования)
  • N9qo8uLOickgx2ZMRZoMye — соль (16 байт)
  • IjZAgcfl7p92ldGxad68LJZdL17lhWy — хеш (24 байта)

Теперь нам нужно описать сервис формирования токенов JWT. В качестве библиотеки воспользуется реализацией от Auth0:

Интерфейс и сама реализация сервиса:

Здесь мы формируем JWT из набора claims (утверждений):

  • iss(Issuer) — издатель токена
  • aud(Audience) — для какого сервиса предназначается токен (в нашем случае для сервиса BookStore)
  • sub(Subject) — идентификатор клиента (clientId)
  • iat — текущее время формирования токена
  • exp — вычисленное время окончания действия токена (выдаем на 5 минут)

Секретный ключ для подписи будет браться из application.properties . Сгенерировать случайный ключ можно следующим образом:

Ответ в случае успешного получения токена:

Ответ в случае ошибки:

Остается описать контроллер:

Укажем в файле application.properties порт, на котором будет запускаться приложение, значение секретного ключа и настройки коннекта к БД:

Запустим приложение и попробуем сгенерировать токен. Для этого зарегистрируем пользователя (считаем, что этот эндпоинт не находится в открытом доступе и это может сделать администратор сервиса):

Используя эти credentials получим токен:

Если расшифровать значение токена (например на сайте jwt.io), то получим следующее содержимое:

Получив такой токен, принимающей стороне необходимо будет сверить подпись и удостовериться в том, что токен выпущен именно для неё (aud) и доверенным сервером (iss).

Авторизация

Нам осталось добавить авторизацию в написанное приложение Bookstore. Откроем проект из предыдущей части и добавим в зависимости библиотеку для работы с JWT (как было показано выше). Также добавим две новых настройки в application.properties:

Одна из них вам уже знакома, а вторую будем использовать для включение/отключения авторизации.

Для проверки полученного токена опишем интерфейс TokenService и его реализацию:

Здесь мы берем значение секретного ключа из настроек приложения, сверяем подпись и проводим все необходимые проверки.

Закроем все эндпоинты и разрешим доступ только при наличии авторизационного токена. Значение авторизационного токена необходимо положить в заголовок следующим образом:

Осталось написать фильтр, который будет осуществлять чтение заголовка и принимать решение об авторизации запроса:

Запускаем второе приложение и пытаемся сделать запрос:

Статус 401 указывает на необходимость авторизоваться. Получим свежий токен и повторим запрос, передав его в заголовке Authorization:

Время действия токена мы выбрали 5 минут, поэтому через этот промежуток времени сервис вернёт статус 403, что будет означать невалидность токена и необходимость получить новый:

В этой части мы познакомились с основами аутентификации и авторизации в веб-приложениях с использованием токенов доступа. В следующей части продолжим улучшать наше приложение, а также познакомимся с паттерном Api Gateway.

Читайте также: