Подключение к базе данных SQL Azure и выполнение запросов с использованием пакета Node.js и mssql npm
Применимо к: База данных SQL Azure
В этом кратком руководстве описывается подключение приложения к базе данных в База данных SQL Azure и выполнение запросов с помощью Node.js и mssql. В этом кратком руководстве описан рекомендуемый подход без пароля для подключения к базе данных.
Безпарольные подключения для разработчиков
Подключения без пароля обеспечивают более безопасный механизм доступа к ресурсам Azure. Следующие шаги на высоком уровне используются для подключения к базе данных SQL Azure с помощью подключений без пароля в этой статье:
- Подготовьте среду для проверки подлинности без пароля.
- Для локальной среды используется ваша личная идентификация. Этот идентификатор можно извлечь из интегрированной среды разработки, CLI или других локальных средств разработки.
- Для облачной среды используется управляемое удостоверение .
- Аутентификация в среде с использованием
DefaultAzureCredential
из библиотеки удостоверений Azure для получения проверенных учетных данных. - Используйте проверенные учетные данные для создания клиентских объектов Azure SDK для доступа к ресурсам.
Дополнительные сведения о безпарольных подключениях можно узнать на хабе безпарольных подключений.
Предварительные условия
- Подписка Azure
- База данных в База данных SQL Azure настроена для проверки подлинности с помощью идентификатора Microsoft Entra (ранее — Azure Active Directory). Вы можете создать базу данных с помощью краткого руководства по созданию базы данных.
- Оболочка с поддержкой Bash
- Node.js LTS
- Visual Studio Code
- Расширение для Visual Studio Code App Service
- последняя версия Azure CLI;
Настройка сервера базы данных
Безопасные подключения без паролей к базе данных SQL Azure требуют определенных конфигураций базы данных. Проверьте следующие параметры на логическом сервере в Azure, чтобы правильно подключиться к База данных SQL Azure в локальных и размещенных средах:
Для локальных подключений разработки убедитесь, что ваш логический сервер настроен так, чтобы разрешить подключение IP-адреса вашего локального компьютера и других служб Azure:
Перейдите на страницу "Сеть " сервера.
Переключите радиокнопку "Выбранные сети", чтобы отобразить дополнительные параметры конфигурации.
Выберите "Добавить IPv4-адрес клиента (xx.xx.xx.xx)", чтобы добавить правило брандмауэра, которое будет разрешать подключения с вашего локального IPv4-адреса. Кроме того, можно выбрать + Добавить правило брандмауэра, чтобы ввести конкретный IP-адрес.
Убедитесь, что установлен флажок разрешить службам и ресурсам Azure доступ к этому серверу .
Предупреждение
Включение параметра Разрешить службам и ресурсам Azure доступ к этому серверу не является рекомендуемой практикой безопасности для рабочих сценариев. Реальные приложения должны реализовать более безопасные подходы, такие как более строгие ограничения брандмауэра или конфигурации виртуальной сети.
Дополнительные сведения о конфигурациях безопасности базы данных см. в следующих ресурсах:
- Настройте правила брандмауэра База данных SQL Azure.
- Настройте виртуальную сеть с частными конечными точками.
На сервере также должна быть включена проверка подлинности Microsoft Entra и назначена учетная запись администратора Microsoft Entra. Для локальных подключений к разработке учетная запись администратора Microsoft Entra должна быть такой, в которую вы также можете войти в Visual Studio или Azure CLI на локальном компьютере. Вы можете проверить, включена ли аутентификация Microsoft Entra на странице Microsoft Entra ID вашего логического сервера.
Если вы используете личную учетную запись Azure, убедитесь, что Microsoft Entra настроен и конфигурирован для базы данных Azure SQL, чтобы назначить вашу учетную запись администратором сервера. Если вы используете корпоративную учетную запись, Microsoft Entra ID уже будет настроен для вас.
Создание проекта
Действия, описанные в этом разделе, создают Node.js REST API.
Создайте новый каталог для проекта и перейдите в него.
Инициализировать проект, выполнив следующую команду в терминале:
npm init -y
Установите необходимые пакеты, используемые в примере кода в этой статье:
npm install mssql express swagger-ui-express yamljs dotenv
Откройте проект в Visual Studio Code.
code .
Откройте файл
package.json
и добавьте следующее свойство и значение после имени , чтобы настроить проект для модулей ESM."type": "module",
Создание кода приложения Express.js
Чтобы создать приложение OpenAPI Express.js, создайте несколько файлов:
Файл | Описание |
---|---|
.env.development |
Файл среды только для локальной разработки. |
index.js |
Основной файл приложения, который запускает приложение Express.js через порт 3000. |
person.js |
Express.js файл API маршрута /person для обработки операций CRUD. |
openapi.js |
Маршрут Express.js /api-docs для интерфейса пользователя обозревателя OpenAPI. Корень перенаправляет на этот маршрут. |
openApiSchema.yml |
Файл схемы OpenAPI 3.0, определяющий API Person. |
config.js |
Файл конфигурации для чтения переменных среды и создания соответствующего объекта подключения mssql. |
database.js |
Класс базы данных для обработки операций CRUD SQL Azure с помощью пакета mssql npm. |
./vscode/settings.json |
Игнорировать файлы по шаблону glob во время развертывания. |
Создайте файл
index.js
и добавьте следующий код:import express from 'express'; // Import App routes import person from './person.js'; import openapi from './openapi.js'; const port = process.env.PORT || 3000; const app = express(); // Connect App routes app.use('/api-docs', openapi); app.use('/persons', person); app.use('*', (_, res) => { res.redirect('/api-docs'); }); // Start the server app.listen(port, () => { console.log(`Server started on port ${port}`); });
Создайте файл маршрута
person.js
и добавьте следующий код:import express from 'express'; import { passwordConfig as SQLAuthentication, noPasswordConfig as PasswordlessConfig } from './config.js'; import { createDatabaseConnection } from './database.js'; const router = express.Router(); router.use(express.json()); const database = await createDatabaseConnection(SQLAuthentication); router.get('/', async (req, res) => { try { // Return a list of persons const persons = await database.readAll(); console.log(`persons: ${JSON.stringify(persons)}`); res.status(200).json(persons); } catch (err) { res.status(500).json({ error: err?.message }); } }); router.post('/', async (req, res) => { try { // add a person const person = req.body; console.log(`person: ${JSON.stringify(person)}`); const rowsAffected = await database.create(person); res.status(201).json({ rowsAffected }); } catch (err) { res.status(500).json({ error: err?.message }); } }); router.get('/:id', async (req, res) => { try { // Get the person with the specified ID const personId = req.params.id; console.log(`personId: ${personId}`); if (personId) { const result = await database.read(personId); console.log(`persons: ${JSON.stringify(result)}`); res.status(200).json(result); } else { res.status(404); } } catch (err) { res.status(500).json({ error: err?.message }); } }); router.put('/:id', async (req, res) => { try { // Update the person with the specified ID const personId = req.params.id; console.log(`personId: ${personId}`); const person = req.body; if (personId && person) { delete person.id; console.log(`person: ${JSON.stringify(person)}`); const rowsAffected = await database.update(personId, person); res.status(200).json({ rowsAffected }); } else { res.status(404); } } catch (err) { res.status(500).json({ error: err?.message }); } }); router.delete('/:id', async (req, res) => { try { // Delete the person with the specified ID const personId = req.params.id; console.log(`personId: ${personId}`); if (!personId) { res.status(404); } else { const rowsAffected = await database.delete(personId); res.status(204).json({ rowsAffected }); } } catch (err) { res.status(500).json({ error: err?.message }); } }); export default router;
Для аутентификации без пароля измените параметр, переданный в
createDatabaseConnection
, сSQLAuthentication
наPasswordlessConfig
.const database = await createDatabaseConnection(PasswordlessConfig);
Создайте файл маршрута
openapi.js
и добавьте следующий код для обозревателя пользовательского интерфейса OpenAPI:import express from 'express'; import { join, dirname } from 'path'; import swaggerUi from 'swagger-ui-express'; import yaml from 'yamljs'; import { fileURLToPath } from 'url'; const __dirname = dirname(fileURLToPath(import.meta.url)); const router = express.Router(); router.use(express.json()); const pathToSpec = join(__dirname, './openApiSchema.yml'); const openApiSpec = yaml.load(pathToSpec); router.use('/', swaggerUi.serve, swaggerUi.setup(openApiSpec)); export default router;
Создайте файл
openApiSchema.yml
и добавьте следующий код, чтобы обозреватель пользовательского интерфейса OpenAPI знал, какие API и модели нужно отобразить:openapi: 3.0.0 info: version: 1.0.0 title: Persons API paths: /persons: get: summary: Get all persons responses: '200': description: OK content: application/json: schema: type: array items: $ref: '#/components/schemas/Person' post: summary: Create a new person requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/Person' responses: '201': description: Created content: application/json: schema: $ref: '#/components/schemas/Person' /persons/{id}: parameters: - name: id in: path required: true schema: type: integer get: summary: Get a person by ID responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/Person' '404': description: Person not found put: summary: Update a person by ID requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/Person' responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/Person' '404': description: Person not found delete: summary: Delete a person by ID responses: '204': description: No Content '404': description: Person not found components: schemas: Person: type: object properties: id: type: integer readOnly: true firstName: type: string lastName: type: string
Настройка объекта подключения mssql
Пакет mssql реализует подключение к База данных SQL Azure путем предоставления параметра конфигурации для типа проверки подлинности.
В Visual Studio Code создайте файл
config.js
и добавьте следующий код конфигурации mssql для проверки подлинности в базе данных SQL Azure.import * as dotenv from 'dotenv'; if(process.env.NODE_ENV === 'development') { dotenv.config({ path: `.env.${process.env.NODE_ENV}`, debug: true }); } // TIP: Port must be a number, not a string! const server = process.env.AZURE_SQL_SERVER; const database = process.env.AZURE_SQL_DATABASE; const port = +process.env.AZURE_SQL_PORT; const type = process.env.AZURE_SQL_AUTHENTICATIONTYPE; const user = process.env.AZURE_SQL_USER; const password = process.env.AZURE_SQL_PASSWORD; export const noPasswordConfig = { server, port, database, authentication: { type }, options: { encrypt: true } }; export const passwordConfig = { server, port, database, user, password, options: { encrypt: true } };
Создание файла переменной локальной среды
Создание файла .env.development
для переменных локальной среды
Добавьте следующий текст и обновите значения для <YOURSERVERNAME>
и <YOURDATABASENAME>
.
AZURE_SQL_SERVER=<YOURSERVERNAME>.database.windows.net
AZURE_SQL_DATABASE=<YOURDATABASENAME>
AZURE_SQL_PORT=1433
AZURE_SQL_AUTHENTICATIONTYPE=azure-active-directory-default
Примечание.
Объекты конфигурации, не содержащие пароли, могут безопасно фиксироваться в системе управления версиями, так как в них отсутствуют такие секреты, как имена пользователей, пароли или ключи доступа.
Добавление кода для подключения к База данных SQL Azure
Создайте файл
database.js
и добавьте следующий код:import sql from 'mssql'; let database = null; export default class Database { config = {}; poolconnection = null; connected = false; constructor(config) { this.config = config; } async connect() { try { this.poolconnection = await sql.connect(this.config); this.connected = true; console.log('Database connected successfully.'); return this.poolconnection; } catch (error) { console.error('Error connecting to the database:', error); this.connected = false; } } async disconnect() { try { if (this.connected) { await this.poolconnection.close(); this.connected = false; console.log('Database disconnected successfully.'); } } catch (error) { console.error('Error disconnecting from the database:', error); } } async executeQuery(query) { const request = this.poolconnection.request(); const result = await request.query(query); return result.rowsAffected[0]; } async create(data) { const request = this.poolconnection.request(); request.input('firstName', sql.NVarChar(255), data.firstName); request.input('lastName', sql.NVarChar(255), data.lastName); const result = await request.query( `INSERT INTO Person (firstName, lastName) VALUES (@firstName, @lastName)` ); return result.rowsAffected[0]; } async readAll() { const request = this.poolconnection.request(); const result = await request.query(`SELECT * FROM Person`); return result.recordsets[0]; } async read(id) { const request = this.poolconnection.request(); const result = await request .input('id', sql.Int, +id) .query(`SELECT * FROM Person WHERE id = @id`); return result.recordset[0]; } async update(id, data) { const request = this.poolconnection.request(); request.input('id', sql.Int, +id); request.input('firstName', sql.NVarChar(255), data.firstName); request.input('lastName', sql.NVarChar(255), data.lastName); const result = await request.query( `UPDATE Person SET firstName=@firstName, lastName=@lastName WHERE id = @id` ); return result.rowsAffected[0]; } async delete(id) { const idAsNumber = Number(id); const request = this.poolconnection.request(); const result = await request .input('id', sql.Int, idAsNumber) .query(`DELETE FROM Person WHERE id = @id`); return result.rowsAffected[0]; } async createTable() { if (process.env.NODE_ENV === 'development') { this.executeQuery( `IF NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'Person') BEGIN CREATE TABLE Person ( id int NOT NULL IDENTITY, firstName varchar(255), lastName varchar(255) ); END` ) .then(() => { console.log('Table created'); }) .catch((err) => { // Table may already exist console.error(`Error creating table: ${err}`); }); } } } export const createDatabaseConnection = async (passwordConfig) => { database = new Database(passwordConfig); await database.connect(); await database.createTable(); return database; };
локальное тестирование приложения.
Приложение готово к локальному тестированию. Убедитесь, что вы вошли в облако Azure в Visual Studio Code с той же учетной записью, что и администратор базы данных.
Запустите приложение с помощью следующей команды. Приложение начинается через порт 3000.
NODE_ENV=development node index.js
Таблица Person создается в базе данных при запуске этого приложения.
В браузере перейдите в обозреватель OpenAPI по адресу http://localhost:3000.
На странице пользовательского интерфейса Swagger разверните метод POST и выберите "Попробовать".
Измените пример JSON, чтобы включить значения свойств. Свойство ID игнорируется.
Выберите "Выполнить" , чтобы добавить новую запись в базу данных. API возвращает успешный ответ.
Разверните метод GET на странице пользовательского интерфейса Swagger и выберите "Попробовать". Выберите "Выполнить", а пользователь, который вы только что создали, возвращается.
Настроить проект для развертывания zip-файла
Создайте папку
.vscode
и создайте файлsettings.json
в папке.Добавьте следующее, чтобы игнорировать переменные среды и зависимости во время развертывания ZIP.
{ "appService.zipIgnorePattern": ["./.env*","node_modules{,/**}"] }
Развертывание в Службу приложений Azure
Приложение готово к развертыванию в Azure. Visual Studio Code может создать службу приложение Azure и развернуть приложение в одном рабочем процессе.
Убедитесь, что приложение остановлено.
Войдите в Azure, если вы еще не сделали этого, выбрав Azure: войти в облако Azure в палитре команд ( + +
В окне Обозреватель Azure в Visual Studio Code щелкните правой кнопкой мыши на узле App Services и выберите Создать новое веб-приложение (расширенный).
Чтобы создать Служба приложений, используйте следующую таблицу:
Подсказка Значение Введите глобально уникальное имя для нового веб-приложения. Введите запрос, например azure-sql-passwordless
. Добавьте в конце уникальную строку, например123
.Выберите группу ресурсов для новых ресурсов. Нажмите кнопку +Создать новую группу ресурсов, а затем выберите имя по умолчанию. Выберите стек сред выполнения Выберите версию LTS Node.js стека. Select an OS (Выберите ОС). Щелкните Linux. Выберите расположение для новых ресурсов. Выберите расположение рядом с вами. Выберите план службы приложений Linux. Выберите Создать новый план службы приложений. Затем выберите имя по умолчанию. Выберите ценовую категорию. Выберите "Бесплатный" (F1). Select an Application Insights resource for your app (Выберите ресурс Application Insights для приложения). выберите Пока пропустить. Подождите уведомления о создании вашего приложения, прежде чем переходить к дальнейшим действиям.
В Обозревателе Azure разверните узел Службы приложений и щелкните правой кнопкой мыши ваше новое приложение.
Выберите "Развернуть в веб-приложении".
Выберите корневую папку проекта JavaScript.
Когда появится всплывающее окно Visual Studio Code, нажмите кнопку "Развернуть".
Когда развертывание завершится, приложение не работает правильно в Azure. Для получения данных необходимо настроить безопасное подключение между Служба приложений и базой данных SQL.
Подключение Службы приложений к базе данных SQL Azure
Для подключения экземпляра службы приложений к базе данных Azure SQL необходимо выполнить следующие действия.
- Создайте управляемую идентификацию для Службы приложений.
- Создайте пользователя базы данных SQL и свяжите его с управляемым удостоверением службы приложений.
- Назначьте роли SQL пользователю базы данных, разрешающим чтение, запись и потенциально другие разрешения.
Существует несколько средств, доступных для реализации следующих действий.
Соединитель служб — это средство, которое упрощает аутентификацию подключений между различными службами в Azure. Соединитель служб в настоящее время поддерживает подключение Службы приложений к базе данных Azure SQL через команду az webapp connection create sql
с использованием Azure CLI. Эта одна команда выполняет три описанных выше шага.
Создайте управляемое удостоверение с помощью Service Connector
Выполните следующую команду в Cloud Shell на портале Azure. Cloud Shell имеет последнюю версию Azure CLI. Замените переменные <>
собственными значениями.
az webapp connection create sql \
-g <app-service-resource-group> \
-n <app-service-name> \
--tg <database-server-resource-group> \
--server <database-server-name> \
--database <database-name> \
--system-identity
Проверка параметров приложения Служба приложений
Изменения, внесенные Service Connector, можно проверить в параметрах App Service.
В Visual Studio Code в обозревателе Azure щелкните правой кнопкой мыши вашу службу приложений и выберите Открыть на портале.
Перейдите на страницу Идентификация для Службы приложений. На вкладке "Системное назначение" статус должен быть"Вкл.". Это значение указывает на то, что системное управляемое удостоверение было активировано для вашего приложения.
Перейдите на страницу конфигурации для службы приложений. На вкладке "Параметры приложения" вы увидите несколько переменных среды, которые уже находились в объекте конфигурации mssql .
AZURE_SQL_SERVER
AZURE_SQL_DATABASE
AZURE_SQL_PORT
AZURE_SQL_AUTHENTICATIONTYPE
Не удаляйте или не изменяйте имена или значения свойств.
Тестирование развернутого приложения
Перейдите по URL-адресу приложения, чтобы проверить, работает ли подключение к База данных SQL Azure. URL-адрес вашего приложения можно найти на странице обзора службы приложений.
Лицо, которое вы создали локально, должно быть отображено в браузере. Поздравляем! Теперь приложение подключено к База данных SQL Azure как в локальных, так и в размещенных средах.
Совет
Если во время тестирования вы получаете ошибку внутреннего сервера 500, это может быть связано с конфигурациями сети базы данных. Убедитесь, что логический сервер настроен с параметрами, описанными в разделе "Настройка базы данных ".
Очистка ресурсов
После завершения работы с База данных SQL Azure удалите ресурс, чтобы избежать непредвиденных затрат.
В строке поиска в портале Azure найдите Azure SQL и выберите соответствующий результат.
Найдите и выберите базу данных в списке баз данных.
На странице "Обзор" базы данных Azure SQL выберите Удалить.
На странице Azure "Вы уверены, что хотите удалить...", которая открывается, введите имя вашей базы данных для подтверждения, а затем нажмите Удалить.
Пример кода
Доступен пример кода для этого приложения: