Поделиться через


Подключение к База данных SQL Azure и запрос с помощью пакета Node.js и mssql npm

Применимо к: База данных SQL Azure

В этом кратком руководстве описывается подключение приложения к базе данных в База данных SQL Azure и выполнение запросов с помощью Node.js и mssql. В этом кратком руководстве описан рекомендуемый подход без пароля для подключения к базе данных.

Бессерверные подключения для разработчиков

Подключения без пароля обеспечивают более безопасный механизм доступа к ресурсам Azure. Следующие высокоуровневые шаги используются для подключения к База данных SQL Azure с помощью бессерверных подключений в этой статье:

  • Подготовьте среду для проверки подлинности без пароля.
    • Для локальной среды используется ваше личное удостоверение. Это удостоверение можно извлечь из интегрированной среды разработки, интерфейса командной строки или других локальных средств разработки.
    • Для облачной среды используется управляемое удостоверение .
  • Проверка подлинности в среде с помощью DefaultAzureCredential библиотеки удостоверений Azure для получения проверенных учетных данных.
  • Используйте проверенные учетные данные для создания клиентских объектов Azure SDK для доступа к ресурсам.

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

Необходимые компоненты

Настройка сервера базы данных

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

  1. Для локальных подключений разработки убедитесь, что логический сервер настроен, чтобы разрешить подключение ip-адреса локального компьютера и других служб Azure:

    • Перейдите на страницу "Сеть " сервера.

    • Переключите переключатель "Выбранные сети", чтобы отобразить дополнительные параметры конфигурации.

    • Выберите " Добавить ip-адрес клиента" (xx.xx.xx.xx.xx), чтобы добавить правило брандмауэра, которое будет включать подключения с адреса IPv4 локального компьютера. Кроме того, можно выбрать + Добавить правило брандмауэра, чтобы ввести конкретный IP-адрес.

    • Убедитесь, что установлен флажок разрешить службам и ресурсам Azure доступ к этому серверу .

      Снимок экрана: настройка правил брандмауэра.

      Предупреждение

      Включение доступа к этому параметру сервера служб и ресурсов Azure не является рекомендуемой практикой безопасности для рабочих сценариев. Реальные приложения должны реализовать более безопасные подходы, такие как более строгие ограничения брандмауэра или конфигурации виртуальной сети.

      Дополнительные сведения о конфигурациях безопасности базы данных см. в следующих ресурсах:

  2. На сервере также должна быть включена проверка подлинности Microsoft Entra и назначена учетная запись администратора Microsoft Entra. Для локальных подключений к разработке учетная запись администратора Microsoft Entra должна быть учетной записью, с помощью azure CLI или Visual Studio. Вы можете проверить, включена ли проверка подлинности Microsoft Entra на странице идентификатора Microsoft Entra на логическом сервере.

    Снимок экрана: включение проверки подлинности Microsoft Entra.

  3. Если вы используете личную учетную запись Azure, убедитесь, что настроена настройка Microsoft Entra и настроена для База данных SQL Azure, чтобы назначить свою учетную запись администратором сервера. Если вы используете корпоративную учетную запись, идентификатор Microsoft Entra, скорее всего, будет настроен для вас.

Создание проекта

Действия, описанные в этом разделе, создают Node.js REST API.

  1. Создайте новый каталог для проекта и перейдите в него.

  2. Инициализировать проект, выполнив следующую команду в терминале:

    npm init -y
    
  3. Установите необходимые пакеты, используемые в примере кода в этой статье:

    npm install mssql express swagger-ui-express yamljs dotenv
    
  4. Откройте проект в Visual Studio Code.

    code .
    
  5. Откройте файл package.json и добавьте следующее свойство и значение после свойства имени, чтобы настроить проект для модулей ESM.

    "type": "module",
    

Создание кода приложения Express.js

Чтобы создать приложение OpenAPI Express.js, создайте несколько файлов:

Файл Description
.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 во время развертывания.
  1. Создайте файл 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}`);
    });
    
  2. Создайте файл маршрута 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 в PasswordlessConfigSQLAuthentication .

    const database = await createDatabaseConnection(PasswordlessConfig);
    
  3. Создайте файл маршрута 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;
    

Настройка объекта подключения mssql

Пакет mssql реализует подключение к База данных SQL Azure путем предоставления параметра конфигурации для типа проверки подлинности.

  1. В 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

  1. Создайте файл 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 с той же учетной записью, что и администратор базы данных.

  1. Запустите приложение с помощью следующей команды. Приложение начинается через порт 3000.

    NODE_ENV=development node index.js
    

    Таблица Person создается в базе данных при запуске этого приложения.

  2. В браузере перейдите в обозреватель OpenAPI по адресу http://localhost:3000.

  3. На странице пользовательского интерфейса Swagger разверните метод POST и выберите "Попробовать".

  4. Измените пример JSON, чтобы включить значения свойств. Свойство ID игнорируется.

    Снимок экрана, показывающий, как протестировать API.

  5. Выберите "Выполнить" , чтобы добавить новую запись в базу данных. API возвращает успешный ответ.

  6. Разверните метод GET на странице пользовательского интерфейса Swagger и выберите "Попробовать". Выберите "Выполнить", а пользователь, который вы только что создали, возвращается.

Настройка проекта для развертывания ZIP

  1. Создайте папку .vscode и создайте файл settings.json в папке.

  2. Добавьте следующее, чтобы игнорировать переменные среды и зависимости во время развертывания ZIP.

    {
        "appService.zipIgnorePattern": ["./.env*","node_modules{,/**}"]
    }
    

Развертывание в Службу приложений Azure

Приложение готово к развертыванию в Azure. Visual Studio Code может создать службу приложение Azure и развернуть приложение в одном рабочем процессе.

  1. Убедитесь, что приложение остановлено.

  2. Войдите в Azure, если вы еще не сделали этого, выбрав Azure: войти в облако Azure в палитре команд (CTRL SHIFT + + P)

  3. В окне Обозревателя Azure в Visual Studio Code щелкните правой кнопкой мыши узел Служба приложений s и выберите "Создать веб-приложение (дополнительно)".

  4. Чтобы создать Служба приложений, используйте следующую таблицу:

    Prompt Значение
    Введите глобально уникальное имя для нового веб-приложения. Введите запрос, например azure-sql-passwordless. После пера уникальная строка, например 123.
    Выберите группу ресурсов для новых ресурсов. Нажмите кнопку +Создать новую группу ресурсов, а затем выберите имя по умолчанию.
    Выберите стек сред выполнения Выберите версию LTS Node.js стека.
    Select an OS (Выберите ОС). Щелкните Linux.
    Выберите расположение для новых ресурсов. Выберите расположение рядом с вами.
    Выберите план Служба приложений Linux. Выберите "Создать новый Служба приложений план". Затем выберите имя по умолчанию.
    Выберите ценовую категорию. Выберите "Бесплатный" (F1).
    Select an Application Insights resource for your app (Выберите ресурс Application Insights для приложения). выберите Пока пропустить.
  5. Подождите, пока не будет создано ваше приложение, прежде чем продолжить работу.

  6. В Обозревателе Azure разверните узел Служба приложений s и щелкните правой кнопкой мыши новое приложение.

  7. Выберите "Развернуть в веб-приложении".

    Снимок экрана: Visual Studio Code в обозревателе Azure с выделенным параметром

  8. Выберите корневую папку проекта JavaScript.

  9. Когда появится всплывающее окно Visual Studio Code, нажмите кнопку "Развернуть".

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

Подключение Служба приложений к База данных SQL Azure

Для подключения экземпляра Служба приложений к База данных SQL Azure необходимо выполнить следующие действия.

  1. Создайте управляемое удостоверение для Служба приложений.
  2. Создайте пользователя базы данных SQL и свяжите его с управляемым удостоверением Служба приложений.
  3. Назначьте роли SQL пользователю базы данных, разрешающим чтение, запись и потенциально другие разрешения.

Существует несколько средств, доступных для реализации следующих действий.

Соединитель служб — это средство, которое упрощает аутентификацию подключений между различными службами в Azure. Соединитель служб в настоящее время поддерживает подключение Служба приложений к базе данных SQL Azure с помощью Azure CLI с помощью az webapp connection create sql команды. Эта одна команда выполняет три описанных выше шага.

Создание управляемого удостоверения с помощью соединителя службы

Выполните следующую команду в 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

Проверка параметров приложения Служба приложений

Изменения, внесенные соединителем службы, можно проверить в параметрах Служба приложений.

  1. В Visual Studio Code в обозревателе Azure щелкните правой кнопкой мыши Служба приложений и выберите "Открыть на портале".

  2. Перейдите на страницу удостоверений для Служба приложений. На вкладке "Назначаемая системой" состояние должно иметь значение "Вкл.". Это значение означает, что управляемое удостоверение, назначаемое системой, было включено для приложения.

  3. Перейдите на страницу конфигурации для Служба приложений. На вкладке "Параметры приложения" вы увидите несколько переменных среды, которые уже находились в объекте конфигурации mssql .

    • AZURE_SQL_SERVER
    • AZURE_SQL_DATABASE
    • AZURE_SQL_PORT
    • AZURE_SQL_AUTHENTICATIONTYPE

    Не удаляйте или не изменяйте имена или значения свойств.

Тестирование развернутого приложения

Перейдите по URL-адресу приложения, чтобы проверить, работает ли подключение к База данных SQL Azure. URL-адрес приложения можно найти на странице обзора Служба приложений.

Пользователь, созданный локально, должен отображаться в браузере. Поздравляем! Теперь приложение подключено к База данных SQL Azure как в локальных, так и в размещенных средах.

Совет

Если во время тестирования вы получаете ошибку внутреннего сервера 500, это может быть связано с конфигурациями сети базы данных. Убедитесь, что логический сервер настроен с параметрами, описанными в разделе "Настройка базы данных ".

Очистка ресурсов

После завершения работы с База данных SQL Azure удалите ресурс, чтобы избежать непредвиденных затрат.

  1. В строке поиска портал Azure найдите SQL Azure и выберите соответствующий результат.

  2. Найдите и выберите базу данных в списке баз данных.

  3. На странице обзора База данных SQL Azure нажмите кнопку "Удалить".

  4. На открывшейся странице Azure необходимо удалить... введите имя базы данных, чтобы подтвердить, а затем нажмите кнопку "Удалить".

Пример кода

Доступен пример кода для этого приложения:

Следующие шаги