Случилось так, что мне пришлось разобраться с тем, как в Service Broker сделать передачу сообщений, используя для аутентификации сертификаты.
Исходные:
— 2 компьютера mf-2007 и mf-1689 (названия взяты от балды [названия рабочих компов]);
— На обоих Microsoft SQL Server 2014.
Задача послать сообщение.
Решение под катом (пошаговая инструкция).
Итак, начнём с mf-1689. Для mf-2007 всё то же самое с точностью до цифр.
Выполнять нужно параллельно на 2-х машинах.
Создаём мастер ключ:
USE [master]
GO
CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'mf_1689';
Создаём логин для пользователя, от имени которого будет проходить авторизация и аутентификация:
CREATE LOGIN sb_mf_1689 with password = 'Pa$$w0rd';
Создадим пользователя в мастере, к нему привяжем сертификат:
CREATE USER sb_mf_1689 FOR LOGIN sb_mf_1689;
Создадим сертификат для аутентификации и сохраним его открытый ключ:
CREATE CERTIFICATE mf_1689_cert
AUTHORIZATION sb_mf_1689
WITH SUBJECT = 'mf_1689';
GO
BACKUP CERTIFICATE mf_1689_cert
TO FILE = 'c:certsmf_1689.cer';
Этот ключик перепишем на соседний компьютер и восстановим из него сертификат для подключения:
CREATE CERTIFICATE pk_2007
AUTHORIZATION sb_mf_1689
FROM FILE = 'c:certsmf_2007.cer';
Создаём конечную точку для сервис брокера и предоставляем нашему пользователю право на коннект через эту конечную точку:
CREATE ENDPOINT mf_1689
STATE = STARTED
AS TCP (LISTENER_PORT = 51001)
FOR SERVICE_BROKER (AUTHENTICATION = CERTIFICATE mf_1689_cert, ENCRYPTION = SUPPORTED ALGORITHM AES);
GO
GRANT CONNECT ON ENDPOINT::mf_1689 TO sb_mf_1689;
Создадим БД, в которой будем держать очереди и сервисы:
CREATE DATABASE sb_db2;
GO
ALTER DATABASE sb_db2 set single_user with rollback immediate;
GO
ALTER DATABASE sb_db2 set new_broker;
GO
ALTER DATABASE sb_db2 set multi_user;
GO
USE sb_db2;
GO
Создадим мастер ключ в новой БД:
CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'mf_1689';
GO
Создадим пользователя:
CREATE USER sb_mf_1689 FOR LOGIN sb_mf_1689;
GO
Для авторизации пользователя внутри БД создадим сертификат и сохраним его:
CREATE CERTIFICATE dlg_1689
WITH SUBJECT = 'mf_1689'
ACTIVE FOR BEGIN_DIALOG = ON;
GO
BACKUP CERTIFICATE dlg_1689
TO FILE = 'c:certsdlg_1689.cer';
GO
Далее файлик с сертификатом перенесём на другой комп и создадим сертификат из файлика:
CREATE CERTIFICATE pkdlg_2007
AUTHORIZATION sb_mf_1689
FROM FILE = 'c:certsdlg_2007.cer';
GO
Создадим объекты брокера (очередь, тип сообщения, контракт, сервис, маршрут):
CREATE QUEUE dbo.Queue_2 WITH STATUS = ON , RETENTION = OFF;
GO
CREATE MESSAGE TYPE msg_sd
VALIDATION = WELL_FORMED_XML;
GO
CREATE CONTRACT cntr_sb
(msg_sd SENT BY ANY);
GO
CREATE SERVICE srv_sb_1689
ON QUEUE dbo.Queue_2
(cntr_sb);
GO
CREATE ROUTE route_srv_sb_db1
WITH SERVICE_NAME = 'srv_sb_2007', ADDRESS = N'TCP://mf-2007:51001';
GO
Создадим привязку для определения учётных данных безопасности:
CREATE REMOTE SERVICE BINDING route_2007
TO SERVICE 'srv_sb_2007'
WITH USER = sb_mf_1689;
GO
И дадим права пользователю на отправку сообщений:
GRANT SEND ON SERVICE::[srv_sb_1689] TO sb_mf_1689;
GO
Если вы проделали всё зеркально на 2-х машинах, то вы готовы к обмену сообщениями:
DECLARE @from_srv SYSNAME = N'srv_sb_1689',
@to_srv SYSNAME = N'srv_sb_2007',
@contract SYSNAME = N'cntr_sb',
@conversation_handle UNIQUEIDENTIFIER
SELECT @conversation_handle = ce.conversation_handle
FROM sys.conversation_endpoints ce WITH (NOLOCK)
INNER JOIN sys.service_contracts sc WITH (NOLOCK)
ON sc.service_contract_id = ce.service_contract_id
WHERE ce.[state] NOT IN ('CD', 'ER', 'DI', 'DO')
AND ce.far_service = @to_srv
AND sc.name = @contract
IF @conversation_handle IS NULL
BEGIN
;BEGIN DIALOG CONVERSATION @conversation_handle
FROM SERVICE @from_srv
TO SERVICE @to_srv
ON CONTRACT @contract
WITH ENCRYPTION = OFF;
END;
DECLARE @message XML = '<body>test_from_sb_1689</body>';
SEND ON CONVERSATION @conversation_handle
MESSAGE TYPE [msg_sd] (@message);
Проверьте, что сообщение ушло в sys.transmission_queue и в очереди на другом компе.