Генри Куи
Создайте защищенные на транспортном уровне Web-сервисы, используя IBM Rational Application Developer V7 и IBM WebSphere Application Server V6.1. Выполните приведенные в этой серии статей, состоящей из трех частей, пошаговые инструкции по разработке Web-сервисов и клиентов, настройке базовой HTTP-аутентификации и настройке протокола HTTP over SSL (HTTPS). В этой первой части серии статей приведено описание процесса создания Web-сервиса для простого приложения-калькулятора. Мы сгенерируем и протестируем клиентов Web-сервиса двух различных типов: Java EE-клиента (Java Platform, Enterprise Edition) и автономного Java-клиента. Также мы рассмотрим обработку определенных пользователем исключительных ситуаций в Web-сервисах.
Введение в систему защиты на транспортном уровне
Защита Web-сервисов может быть реализована на двух уровнях: на транспортном уровн е и уровне сообщений . Давайте рассмотрим их подробнее:
- Защита на транспортном уровне. Защита на транспортном уровне представляет собой механизм защиты точка-точка, который можно использовать для идентификации и аутентификации субъектов, обеспечения целостности сообщений и конфиденциальности. HTTP, самый используемый в интернете коммуникационный протокол, в настоящее время также является самым популярным протоколом для Web-сервисов. HTTP по своей сути является незащищенным протоколом, поскольку вся информация передается обычным текстом между не аутентифицированными субъектами по незащищенной сети. При использовании системы защиты на транспортном уровне соединение между клиентом и сервером приложений обычно защищено при помощи протокола Secure Sockets Layer (SSL), а клиент и сервер аутентифицируют подлинность друг друга и взаимодействуют при помощи зашифрованных сообщений. В системе защиты на транспортном уровне взаимодействие шифруется полностью.
- Защита на уровне сообщений. Защита на уровне сообщений представляет собой подход, когда вся информация, относящаяся к системе защиты, инкапсулируется в SOAP-сообщение. Защита на уровне сообщений обеспечивает защиту при помощи маркера имени пользователя (user name token), XML-шифрования и цифровых подписей. Защита на уровне сообщений основывается на спецификации WS-Security. Она часто применяется в сочетании с защитой на транспортном уровне.
В данном учебном руководстве рассказывается, как защитить Web-сервисы на транспортном уровне, используя две технологии: HTTPS и базовую HTTP-аутентификацию.
HTTPS
HTTPS позволяет выполнять аутентификацию через сертификаты на стороне клиента и на стороне сервера. SSL - это протокол, который передает взаимодействия по сети интернет в зашифрованном виде. Он гарантирует передачу и неизменность этой информации, а также то, что она придет только на тот сервер, для которого предназначена. HTTPS Web-сервисы можно применять со всеми типами клиентов, включая Java EE-клиенты и автономные Java-клиенты.
В настоящее время HTTPS с сертификатами сервера является наиболее широко используемой конфигурацией в Web. В такой конфигурации сервер должен предоставить свой сертификат клиенту, для того чтобы он определил идентичность сервера. Клиенту не нужно предоставлять свой собственный сертификат серверу, для того чтобы сервер определил идентичность клиента. Иными словами, клиент может аутентифицировать сервер, а сервер не может аутентифицировать клиента. Однако можно использовать HTTPS совместно с базовой аутентификацией, которая позволяет серверу тоже аутентифицировать клиента.
Базовая HTTP-аутентификация
Простым способом предоставить аутентификационные данные для клиента Web-сервиса является базовая HTTP-аутентификация с защищенной оконечной точкой сервиса. Информация для базовой аутентификации расположена в HTTP-заголовке, который содержит SOAP-запрос. Когда сервер приложений получает HTTP-запрос, извлекаются имя пользователя и пароль, которые затем проверяются механизмом аутентификации, специфичным для сервера. Для предотвращения возможности непосредственного чтения имени пользователя и пароля кем-либо еще, перед передачей они кодируются в последовательность символов base-64.
Базовая HTTP-аутентификация отличается от поддержки базовой аутентификации, предоставляемой WS-Security. Информация для базовой аутентификации, предоставляемая WS-Security, представляет собой SOAP-заголовок , тогда как информация для базовой HTTP-аутентификации представляет собой HTTP-заголовок .
Базовая аутентификация имеет недостатки в системе защиты: информация для аутентификации передается в кодировке base-64, декодировать которую не составляет труда. Передача информации в кодировке base-64 почти так же незащищена, как и открытый текст. Рекомендуется передавать данные по протоколу HTTPS.
В настоящее время широко применяется комбинация базовой HTTP-аутентификации с HTTPS, поскольку она решает следующие задачи системы защиты:
- Аутентификация. Клиент Web-сервиса аутентифицирует себя сервису, передавая закодированное в формате base-64 имя пользователя и пароль в HTTP-заголовке авторизации. Web-сервис аутентифицирует себя клиенту, представляя ему свой сертификат.
- Авторизация. После успешной аутентификации клиента при помощи базовой HTTP-аутентификации, идентичность пользователя ассоциируется с запросом. На базе идентичности принимается решение по авторизации. Это выполняется Java EE-сервером на основе модели системы защиты Java EE с целью предоставления только авторизованного доступа к методам сервлетов, JSP-страницам (JavaServer Pages) и EJB-компонентам (Enterprise JavaBeans).
- Конфиденциальность. HTTPS обеспечивает шифрование, которое гарантирует невозможность третьей стороне дешифровать данные, передаваемые между клиентом и сервером по сети. Базовая HTTP-аутентификация тоже шифруется, благодаря SSL.
- Целостность. HTTPS гарантирует неизменность данных, передаваемых между клиентом и сервером по сети.
Настройка серверов
В данном руководстве мы будем использовать два экземпляра WebSphere Application Server: на первом сервере размещены Web-сервисы, а на втором - клиент Web-сервисов. Нужны два сервера для раздельного размещения Web-сервиса и клиента, потому что необходимо обеспечить ясное представление об SSL-конфигурациях для Web-сервиса и клиента, которые рассматриваются в третьей части данной серии статей (EN).
В WebSphere Application Server V6 или старше информация среды времени исполнения создается в рамках профиля (profile). Если нужно создать новую конфигурацию сервера, необходимо создать новый профиль. Rational Application Developer разрешает одновременное выполнение нескольких конфигураций сервера и сред тестирования на одном и том же рабочем месте.
По умолчанию при установке Rational Application Developer создается WebSphere Application Server, который использует профиль AppSrv01. Для создания нового профиля применяется программа управления профилями, а затем создается второй сервер, которому назначается новый профиль.
Настройка сервера для провайдера Web-сервисов
- Запустите Rational Application Developer.
- После появления диалогового окна Workspace Launcher введите полный путь к месторасположению рабочей области (workspace), как показано на рисунке 1:
C:\workspace\WebService
.
Рисунок 1. Workspace Launcher
- Закройте открывшуюся страницу Welcome. Вы находитесь в перспективе J2EE.
- Перейдите в закладку Servers в нижней панели.
- Должен отобразиться сервер WebSphere Application Server V6.1, как показано на рисунке 2. Этот сервер создается по умолчанию при установке Rational Application Developer.
Рисунок 2. Окно Servers
- Выполните двойной щелчок левой кнопкой мыши на WebSphere Application Server v6.1, чтобы открыть редактор серверов.
- В разделе General измените имя сервера с WebSphere Application Server v6.1 на
WAS v6.1 for Web service provider
.
- Выполните операцию сохранения и закройте редактор серверов.
Создание сервера для потребителя Web-сервисов
- Для создания нового профиля WebSphere Application Server V6.1 при помощи программы управления профилями WebSphere в рабочей среде (workbench) выберите Window > Preferences.
- В окне Preferences разверните Server > WebSphere.
- В списке WebSphere v6.0 and v6.1 local server profile management выберите WebSphere Application Server v6.1. В списке WebSphere profiles defined in the runtime selected above вы должны увидеть AppSrv01, как показано на рисунке 3. AppSrv01 используется сервером WebSphere Application Server V6.1 для провайдера Web-сервисов, которого вы только что настроили.
Рисунок 3. Программа создания профилей WebSphere
- Нажмите кнопку Create рядом со списком WebSphere profiles defined in the runtime selected above, в котором перечислены профили, определенные для выбранной в данный момент среды времени исполнения.
- На странице Welcome to the Profile Management Tool нажмите кнопку Next.
- На странице Environment selection нажмите кнопку Next.
- На странице Profile Creation Options выберите Typical profile creation и нажмите кнопку Next.
- На странице Administrative Security снимите отметку с поля Enable administrative security и нажмите кнопку Next.
- На странице Profile Creation Summary просмотрите настройки профиля. Обратите внимание, что для созданного вами нового профиля значения портов были увеличены на единицу, для того чтобы новый профиль не конфликтовал с существующим.
- Нажмите кнопку Create.
- На странице Profile Creation Complete снимите отметку с поля Launch the First steps console, а затем нажмите кнопку Finish. Вернувшись на страницу Preferences, вы увидите, что новый профиль AppSrv02 появился в списке WebSphere profiles defined in the runtime selected above.
- Щелкните правой кнопкой мыши в окне Servers и выберите New > Server.
- В диалоговом окне Define a New Server выберите WebSphere v6.1 Server и нажмите кнопку Next.
- В диалоговом окне WebSphere Server Settings выберите AppSrv02 в качестве имени профиля WebSphere. В остальных полях оставьте значения по умолчанию и нажмите кнопку Finish.
- Сервер создается и отображается в окне Servers как WebSphere v6.1 @ localhost.
- Выполните двойной щелчок левой кнопкой мыши на WebSphere v6.1 @ localhost для открытия редактора серверов.
- В разделе General измените имя сервера с WebSphere v6.1 @ localhost на
WAS v6.1 for Web service consumer
.
- Выполните операцию сохранения и закройте редактор серверов. Теперь у вас должно отображаться два сервера в окне Servers, как показано на рисунке 4.
Рисунок 4. Список серверов
Создание Java bean-компонента
Теперь создадим приложение Calculator для выполнения простых математических операций, таких как сложение, вычитание, умножение и деление. Если делитель в операции деления равен 0, метод перехватывает исключительную ситуацию ArithmeticException
и генерирует DivideByZeroException
, которая является исключительной ситуацией, определенной пользователем. Это заставит клиента Web-сервисов обработать возможную исключительную ситуацию деления на ноль.
Настройка сервера для провайдера Web-сервисов
- Выберите File > New > Project > Dynamic Web Project и введите
Calculator
в качестве имени проекта, как показано на рисунке 5.
Рисунок 5. Создание динамического Web-проекта
- Нажмите кнопку Finish. Если появится запрос на переход в перспективу Web, нажмите кнопку No. Оставайтесь в перспективе J2EE.
- В Project Explorer щелкните правой кнопкой мыши на проекте Calculator и выберите New > Class.
- Введите
com.ibm
в качестве имени пакета и Calculator
в качестве имени Java-класса, как показано на рисунке 6.
- Нажмите кнопку Finish.
Рисунок 6. Создание нового Java-класса
- Скопируйте код
Calculator.java
, приведенный в листинге 1, в Java-редактор.
- Сохраните файл.
Листинг 1. Calculator.java
package com.ibm;
public class Calculator {
public Calculator() {
}
public int add(int i, int j) {
return i + j;
}
public int subtract(int i, int j) {
return i - j;
}
public int multiply(int i, int j) {
return i * j;
}
/*
* В Java результат целочисленного деления всегда имеет тип integer,
* остаток отбрасывается.
*/
public int divide(int a, int b) throws DivideByZeroException {
try {
return a / b;
} catch (ArithmeticException e) {
throw new DivideByZeroException();
}
}
}
|
Должны появиться ошибки компиляции, поскольку мы еще не создали DivideByZeroException.java.
- В Package Explorer щелкните правой кнопкой мыши на пакете com.ibm > New > Class.
- Введите
DivideByZeroException
в качестве имени класса и нажмите кнопку Finish.
- Скопируйте
DivideByZeroException.java
из листинга 2 в Java-редактор и сохраните файл.
Листинг 2. DivideByZeroException.java
package com.ibm;
public class DivideByZeroException extends Exception {
public DivideByZeroException() {
super();
}
}
|
Ошибки компиляции должны исчезнуть.
Создание Web-сервисов
Создание Web-сервисов с использованием мастера Web services
Теперь можно использовать мастер Web services для представления существующего приложения Calculator в виде Web-сервиса. Такой подход называется подходом "снизу вверх", когда Web-сервис создается на базе существующей бизнес-логики в Java bean-компонентах или EJB-компонентах.
- В окне Servers щелкните правой кнопкой мыши на WAS v6.1 for Web services provider и выберите Start. Запуск сервера может занять пару минут.
- В Package Explorer щелкните правой кнопкой на Java-классе Calculator и выберите Web Services > Create Web service, как показано на рисунке 7.
Рисунок 7. Мастер Web services
- Нажмите ссылку Server: WebSphere v6.1 Server для отображения диалогового окна Service Deployment Configuration.
- Разверните папку Existing Servers.
- Выберите WAS v6.1 for Web service provider в поле Server и IBM WebSphere JAX-RPC в поле Web service runtime, как показано на рисунке 8.
- Нажмите кнопку OK.
Рисунок 8. Выбор сервера и системы времени исполнения Web-сервисов
- Нажмите кнопку Next.
- В диалоговом окне Service Endpoint Interface Selection оставьте значения по умолчанию и нажмите кнопку Next.
- В диалоговом окне Web Service Java Bean Identity оставьте значения по умолчанию и нажмите кнопку Next.
- Нажмите кнопку Finish.
Тестирование Web-сервисов с использованием Web Services Explorer
Быстрый способ протестировать Web-сервисы - использовать Web Services Explorer, JSP Web-приложение, выполняемое механизмом сервлетов Apache Tomcat, который содержится в Eclipse. Web Services Explorer использует WSDL (Web Services Description Language) для интерпретации SOAP-запроса. Возвращаемый параметр извлекается, и значения отображаются в предопределенном формате. Этот процесс не включает в себя маршаллизацию и демаршаллизацию данных.
Для тестирования Web-сервисов:
- В Project Explorer разверните папку JSR-109 Web Services и Services.
- Щелкните правой кнопкой мыши на CalculatorService и выберите Test with Web Services Explorer, как показано на рисунке 9.
Рисунок 9. Запуск Web Services Explorer
- После открытия Web Services Explorer выберите один из методов (например, add).
- Панель Actions справа отображает простой интерфейс, позволяющий вводить значения параметров метода. Введите значения для параметров i и j, а затем нажмите кнопку Go.
- Результат активизации Web-сервиса появляется в панели Status в нижней правой части Web Services Explorer, как показано на рисунке 10.
Рисунок 10. Тестирование с использованием Web Services Explorer
- Выполните двойной щелчок левой кнопкой мыши в панели Status для увеличения ее размеров.
- Выберите Source для просмотра SOAP-сообщений в виде необработанного XML, как показано на рисунке 11.
Рисунок 11. SOAP-запрос и ответ
- Закройте Web Services Explorer.
Создание Java EE-клиента Web-сервисов
Rational Application Developer позволяет сгенерировать клиента Web-сервисов в виде Java EE-клиента (или в виде Web-клиента, EJB-клиента и клиентского приложения) и в виде автономного Java-клиента. В данном разделе мы сгенерируем Web-клиента Web-сервисов.
Генерирование клиента Web-сервиса в Web-проекте
Для генерирования артефактов клиента Web-сервисов, таких как прокси Web-сервисов, обнаружитель сервиса, интерфейс сервиса или заглушка (stub), можно использовать мастер Web services client generation. Мастер генерирует также пример Web-приложения для демонстрации того, как активизировать прокси Web-сервисов.
- В окне Servers щелкните правой кнопкой мыши на WAS v6.1 for Web services consumer и выберите Start. Запуск сервера может занять несколько минут.
- В Project Explorer разверните папку JSR-109 Web Services и Services.
- Щелкните правой кнопкой мыши на CalculatorService и выберите Generate Client.
- Нажмите ссылку Server: WebSphere v6.1 Server для отображения диалогового окна Service Deployment Configuration.
- Разверните папку Existing Servers, выберите WAS v6.1 for Web services consumer в поле Server и IBM WebSphere JAX-RPC в поле Web service runtime, как показано на рисунке 12.
- Нажмите кнопку OK.
Рисунок 12. Окно Client Environment Configuration
- Нажмите ссылку Client project: Calculator для отображения диалогового окна Specify Client Project Settings.
- Введите
CalculatorWebClient
в качестве имени проекта клиента. Убедитесь в том, что в поле Client Project Type выбран вариант Dynamic Web Project, а в поле Client EAR Project выбран CalculatorWebClientEAR, как показано на рисунке 13.
- Нажмите кнопку OK.
Рисунок 13. Указание настроек проекта клиентского приложения
- В диалоговом окне Web Service Client переместите ползунок вверх до позиции Test, как показано на рисунке 14. При этом выберется вариант тестирования сервиса с использованием примера JSP-приложения.
- Нажмите кнопку Next.
Рисунок 14. Диалоговое окно Web Service Client
- В диалоговом окне Web Service Proxy Page оставьте значения по умолчанию (без защиты) и нажмите кнопку Next.
- В диалоговом окне Web Service Client Test оставьте значения по умолчанию (без защиты) и нажмите кнопку Finish. Появляется JSP-клиент Sample.
- Протестируйте методы сложения, вычитания, умножения и деления для проверки корректности работы Web-сервисов, как показано на рисунке 15.
Рисунок 15. Web Services Test Client
- Нажмите кнопку divide. Введите
2
в поле a и 0
в поле b.
- Нажмите кнопку Invoke. Вы должны увидеть следующий результат:
exception: com.ibm.DivideByZeroException
JSP-клиент предназначен для демонстрационных целей; он не обрабатывает исключительные ситуации. Для обработки исключительных ситуаций необходимо писать специализированный код.
Обработка исключительных ситуаций в Web-сервисах
Когда Web-сервис генерирует исключительную ситуацию для указания возникновения ошибки, механизм WebSphere Web services преобразовывает исключительную ситуацию в SOAP-ошибку и возвращает ее в SOAP-ответе. На стороне клиента WebSphere Web services преобразовывает SOAP-ошибку в исключительную ситуацию Java.
Если пользователь вводит 0
в качестве делителя операции деления, Web-сервис генерирует DivideByZeroException
, которая является исключительной ситуацией, определяемой пользователем. На стороне клиента сгенерированный Web-сервис переправляет исключительную ситуацию клиенту таким образом, чтобы клиент мог перехватить определяемую пользователем исключительную ситуацию и отобразить читабельное сообщение на JSP-странице.
Для написания специализированного кода обработки исключительной ситуации, определяемой пользователем, выполните следующие действия:
- В Package Explorer разверните CalculatorWebClient, выберите WebContent > sampleCalculatorProxy и откройте Result.jsp.
- Проверьте исходный код. Вы можете увидеть, что прокси Web-сервисов (com.ibm.CalculatorProxy) активизируется из этой JSP-страницы.
- Перейдите в закладку Source и добавьте следующую строку в начало Result.jsp:
<%@page import="com.ibm.DivideByZeroException"%>
- Найдите две следующие строки:
int divide39mtemp = sampleCalculatorProxyid.divide(a_8idTemp,b_9idTemp);
String tempResultreturnp40 = org.eclipse.jst.ws.util.JspUtils.markup(String.valueOf(divide39mtemp));
Замените их на код, приведенный в листинге 4.
Листинг 4. Добавление кода обработки исключительной ситуации
String tempResultreturnp40;
try {
int divide39mtemp = sampleCalculatorProxyid.divide(a_8idTemp, b_9idTemp);
tempResultreturnp40 =
org.eclipse.jst.ws.util.JspUtils.markup(String.valueOf(divide39mtemp));
} catch (DivideByZeroException e) {
tempResultreturnp40 = "Can't divide by zero!";
}
|
- Сохраните файл. В правой нижней части рабочей среды вы должны увидеть операцию публикации. Если сделать какие-либо изменения в JSP-файле и сохранить файл во время работы сервера, можно подождать завершения интервала автоматической публикации, для того чтобы изменения отобразились на сервере. Перезапускать сервер не обязательно.
- После завершения публикации снова протестируйте метод
divide()
. Введите 2
в поле a и 0
в поле b.
- Нажмите кнопку Invoke. Вы должны увидеть сообщение:
Can't divide by zero!
Создание автономного Java-клиента Web-сервисов
WebSphere Application Server V6.1 предоставляет реализацию неуправляемого клиентского приложения, основанную на спецификации Java API for XML-based RPC (JAX-RPC) 1.1. Thin Client for JAX-RPC вместе с WebSphere Application Server является средой неуправляемых и автономных Java-клиентов, позволяющей выполнять клиентские приложения JAX-RPC Web-сервисов для активизации Web-сервисов, размещенных на сервере приложений. .jar-файл Thin Client for JAX-RPC, com.ibm.ws.webservices.thinclient_6.1.0.jar, расположен в вашем каталоге %RAD installation root%\runtimes\base_v61\runtimes.
- В Project Explorer разверните папку JSR-109 Web Services и Services. Щелкните правой кнопкой мыши на CalculatorService и выберите Generate Client.
- Нажмите ссылку Client project: Calculator для отображения диалогового окна Specify Client Project Settings.
- Введите
CalculatorJavaClient
в качестве имени проекта клиента и Java Utility Project в качестве его типа (см. рисунок 16).
- Нажмите кнопку OK. Клиент Web-сервисов генерируется в Java-проекте.
Рисунок 16. Указание параметров проекта клиента
- Нажмите кнопку Next.
- На странице Web Service Proxy нажмите кнопку Finish.
Теперь создадим Java-класс для активизации сгенерированного прокси Web-сервиса:
- В Package Explorer разверните проект CalculatorJavaClient и выберите src.
- Щелкните правой кнопкой мыши на пакете com.ibm и выберите New > Class.
- Введите
TestCalculator
в качестве имени класса, отметьте флажок public static void main(String[] args), а затем нажмите кнопку Finish.
- Скопируйте код из листинга 5 в Java-редактор.
Листинг 5. TestCalculator.java
package com.ibm;
import java.rmi.RemoteException;
public class TestCalculator {
public static void main(String[] args) {
try {
CalculatorProxy proxy = new CalculatorProxy();
System.out.println("2 + 2 = " + proxy.add(2, 2));
System.out.println("2 - 2 = " + proxy.subtract(2, 2));
System.out.println("4 * 2 = " + proxy.multiply(4, 2));
System.out.println("4 / 2 = " + proxy.divide(4, 2));
System.out.print("4 / 0 = ");
System.out.print(proxy.divide(4, 0));
} catch (DivideByZeroException e) {
System.out.println("Error: can't divide by zero!");
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
|
- Щелкните правой кнопкой мыши на проекте CalculatorJavaClient и выберите Properties.
- Нажмите кнопку Java Build Path и выберите закладку Libraries.
- Выберите элемент WebSphere Application Server v6.1 [WebSphere Application Server v6.1], затем нажмите кнопку Remove, поскольку автономный Java-клиент не имеет доступа ко всем библиотекам времени исполнения WebSphere.
- Нажмите кнопку Add External JARs и добавьте файл com.ibm.ws.webservices.thinclient_6.1.0.jar, который расположен в каталоге %RAD installation root%\runtimes\base_v61\runtimes. Путь компоновки Java должен выглядеть примерно так, как показано на рисунке 17.
- Нажмите кнопку OK.
Рисунок 17. Путь компоновки Java
- В Package Explorer разверните проект CalculatorJavaClient и выберите src > com.ibm.
- Откройте CalculatorProxy.java и найдите строку
private boolean _useJNDI = true;
- Измените значение _useJNDI на false, поскольку автономный Java-клиент выполняется вне контейнера Java EE и не может использовать Java Naming and Directory Interface (JNDI):
private boolean _useJNDI = false;
- Щелкните правой кнопкой мыши на TestCalculator.java и выберите Run As > Java Application. На консоли должна отобразиться следующая информация:
12-Nov-2007 10:31:10 PM com.ibm.ws.ssl.config.SSLConfigManager
INFO: ssl.disable.url.hostname.verification.CWPKI0027I
2 + 2 = 4
2 - 2 = 0
4 * 2 = 8
4 / 2 = 2
4 / 0 = Error: can't divide by zero!
Отличная работа! Вы завершили процесс создания Web-сервисов и клиента Web-сервисов при помощи Rational Application Developer.
Заключение
Rational Application Developer значительно упрощает и автоматизирует процесс создания WS-I-совместимых, готовых к взаимодействию приложений для Web-сервисов, а также повышает производительность. В данной части этой серии статей вы узнали, как создать, развернуть и протестировать приложения для Web-сервисов, используя Rational Application Developer V7 и WebSphere Application Server V6.1. Во второй части мы рассмотрим пошаговые инструкции по настройке базовой HTTP-аутентификации.
Ссылки по теме