Nawiązywanie połączenia z usługą Azure SQL Database i wykonywanie zapytań względem usługi Azure SQL Database przy użyciu pakietu npm Node.js i mssql
Dotyczy:Azure SQL Database
W tym przewodniku Szybki start opisano sposób łączenia aplikacji z bazą danych w usłudze Azure SQL Database i wykonywania zapytań przy użyciu Node.js i mssql. Ten szybki start jest zgodny z zalecanym podejściem bez użycia hasła do łączenia się z bazą danych.
Połączenia bez hasła dla deweloperów
Połączenia bez hasła oferują bezpieczniejszy mechanizm uzyskiwania dostępu do zasobów platformy Azure. Następujące ogólne kroki służą do nawiązywania połączenia z usługą Azure SQL Database przy użyciu połączeń bez hasła w tym artykule:
- Przygotuj środowisko do uwierzytelniania bez hasła.
- W środowisku lokalnym: Używana jest Twoja tożsamość osobista. Tę tożsamość można uzyskać ze środowiska IDE, interfejsu wiersza polecenia lub innych lokalnych narzędzi programistycznych.
- W środowisku chmury: używana jest tożsamość zarządzana.
- Uwierzytelnij się w środowisku przy użyciu
DefaultAzureCredential
z biblioteki Azure Identity, aby uzyskać zweryfikowane poświadczenie. - Użyj zweryfikowanego poświadczenia, aby utworzyć obiekty klienta zestawu Azure SDK na potrzeby dostępu do zasobów.
Więcej informacji na temat połączeń bez hasła można uzyskać w centrum bez hasła.
Wymagania wstępne
- Subskrypcja platformy Azure
- Baza danych w usłudze Azure SQL Database skonfigurowana do uwierzytelniania przy użyciu identyfikatora Entra firmy Microsoft (dawniej Azure Active Directory). Możesz utworzyć ją, korzystając z Przewodnika szybkiego uruchamiania tworzenia bazy danych.
- Powłoka obsługująca Bash
- Node.js LTS
- Visual Studio Code
- Rozszerzenie usługi App Service programu Visual Studio Code
- Najnowsza wersja interfejsu wiersza polecenia platformy Azure
Konfigurowanie serwera bazy danych
Bezpieczne, bez hasła połączenia z usługą Azure SQL Database wymagają pewnych konfiguracji bazy danych. Sprawdź następujące ustawienia na serwerze logicznym na platformie Azure , aby prawidłowo nawiązać połączenie z usługą Azure SQL Database w środowiskach lokalnych i hostowanych:
W przypadku lokalnych połączeń programistycznych upewnij się, że serwer logiczny jest skonfigurowany tak, aby zezwolić na nawiązywanie połączenia z adresem IP komputera lokalnego i innymi usługami platformy Azure:
Przejdź do strony Sieć serwera.
Przełącz przycisk radiowy Wybrane sieci, aby wyświetlić dodatkowe opcje konfiguracji.
Wybierz pozycję Dodaj adres IPv4 klienta (xx.xx.xx.xx.xx ), aby dodać regułę zapory, która umożliwi połączenia z adresu IPv4 komputera lokalnego. Alternatywnie możesz również wybrać pozycję + Dodaj regułę zapory, aby wprowadzić konkretny adres IP.
Upewnij się, że pole wyboru Zezwalaj usługom i zasobom platformy Azure na dostęp do tego serwera jest zaznaczone.
Ostrzeżenie
Włączenie opcji Zezwalaj usługom i zasobom platformy Azure na dostęp do tego ustawienia serwera nie jest zalecaną praktyką zabezpieczeń w scenariuszach produkcyjnych. Rzeczywiste aplikacje powinny implementować bezpieczniejsze podejścia, takie jak silniejsze ograniczenia zapory lub konfiguracje sieci wirtualnej.
Więcej informacji na temat konfiguracji zabezpieczeń bazy danych można uzyskać w następujących zasobach:
- Konfigurowanie reguł zapory usługi Azure SQL Database.
- Konfigurowanie sieci wirtualnej z prywatnymi punktami końcowymi.
Serwer musi również mieć włączone uwierzytelnianie Microsoft Entra i mieć przypisane konto administratora firmy Microsoft Entra. W przypadku lokalnych połączeń konto administratora Microsoft Entra powinno być kontem, na które można się również zalogować do programu Visual Studio lub Azure CLI lokalnie. Możesz sprawdzić, czy serwer ma włączone uwierzytelnianie Microsoft Entra na stronie Microsoft Entra ID twojego serwera logicznego.
Jeśli używasz osobistego konta platformy Azure, upewnij się, że masz skonfigurowaną usługę Microsoft Entra dla Azure SQL Database, aby przypisać swoje konto jako administratora serwera. Jeśli używasz konta firmowego, Microsoft Entra ID jest prawdopodobnie już skonfigurowany.
Tworzenie projektu
Kroki opisane w tej sekcji umożliwiają utworzenie interfejsu API REST Node.js.
Utwórz nowy katalog dla projektu i przejdź do niego.
Zainicjuj projekt, uruchamiając następujące polecenie w terminalu:
npm init -y
Zainstaluj wymagane pakiety używane w przykładowym kodzie w tym artykule:
npm install mssql express swagger-ui-express yamljs dotenv
Otwórz projekt w programie Visual Studio Code.
code .
Otwórz plik
package.json
i dodaj następującą właściwość i wartość po właściwości name w celu skonfigurowania projektu dla modułów ESM."type": "module",
Tworzenie kodu aplikacji Express.js
Aby utworzyć aplikację Express.js OpenAPI, utworzysz kilka plików:
Plik | opis |
---|---|
.env.development |
Lokalny plik środowiska przeznaczony wyłącznie do rozwoju. |
index.js |
Główny plik aplikacji, który uruchamia aplikację Express.js na porcie 3000. |
person.js |
Express.js /person route API plik do obsługi operacji CRUD. |
openapi.js |
Ścieżka Express.js /api-docs dla interfejsu użytkownika eksploratora OpenAPI. Root przekierowuje do tej ścieżki. |
openApiSchema.yml |
Plik schematu OpenAPI 3.0 definiujący API Osób. |
config.js |
Plik konfiguracji do odczytywania zmiennych środowiskowych i konstruowania odpowiedniego obiektu połączenia mssql. |
database.js |
Klasa bazy danych do obsługi operacji CRUD usługi Azure SQL przy użyciu pakietu npm mssql . |
./vscode/settings.json |
Ignoruj pliki według wzorca glob podczas wdrażania. |
Utwórz plik
index.js
i dodaj następujący kod: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}`); });
Utwórz plik trasy
person.js
i dodaj następujący kod: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;
W przypadku uwierzytelniania bez hasła zmień przekazywany parametr z
SQLAuthentication
naPasswordlessConfig
wcreateDatabaseConnection
.const database = await createDatabaseConnection(PasswordlessConfig);
Utwórz plik trasy
openapi.js
i dodaj następujący kod dla eksploratora OpenAPI UI.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;
Utwórz plik
openApiSchema.yml
i dodaj następujący kod, aby eksplorator interfejsu użytkownika OpenAPI wiedział, jakie API i modele mają być wyświetlane.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
Konfigurowanie obiektu połączenia mssql
Pakiet mssql implementuje połączenie z usługą Azure SQL Database, zapewniając ustawienie konfiguracji dla typu uwierzytelniania.
W programie Visual Studio Code utwórz plik
config.js
i dodaj następujący kod konfiguracji mssql w celu uwierzytelniania w usłudze Azure SQL Database.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 } };
Tworzenie lokalnego pliku zmiennej środowiskowej
Tworzenie pliku .env.development
dla lokalnych zmiennych środowiskowych
Dodaj poniższy tekst i zaktualizuj swoimi wartościami dla <YOURSERVERNAME>
oraz <YOURDATABASENAME>
.
AZURE_SQL_SERVER=<YOURSERVERNAME>.database.windows.net
AZURE_SQL_DATABASE=<YOURDATABASENAME>
AZURE_SQL_PORT=1433
AZURE_SQL_AUTHENTICATIONTYPE=azure-active-directory-default
Uwaga
Obiekty konfiguracji bez hasła są bezpieczne do zatwierdzania w systemie kontroli wersji, ponieważ nie zawierają żadnych tajnych informacji, takich jak nazwy użytkowników, hasła lub klucze dostępu.
Dodawanie kodu w celu nawiązania połączenia z usługą Azure SQL Database
Utwórz plik
database.js
i dodaj następujący kod: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; };
Lokalne przetestowanie aplikacji
Aplikacja jest gotowa do testowania lokalnie. Upewnij się, że zalogowano się do chmury platformy Azure w programie Visual Studio Code przy użyciu tego samego konta, które zostało ustawione jako administrator bazy danych.
Uruchom aplikację za pomocą następującego polecenia. Aplikacja jest uruchamiana na porcie 3000.
NODE_ENV=development node index.js
Tabela Person jest tworzona w bazie danych podczas uruchamiania tej aplikacji.
W przeglądarce przejdź do eksploratora interfejsu OpenAPI pod adresem http://localhost:3000.
Na stronie Swagger UI rozwiń metodę POST i wybierz pozycję Wypróbuj.
Zmodyfikuj przykładowy kod JSON, aby uwzględnić wartości właściwości. Właściwość ID jest ignorowana.
Wybierz pozycję Wykonaj , aby dodać nowy rekord do bazy danych. API zwraca odpowiedź pomyślnie.
Rozwiń metodę GET na stronie interfejsu użytkownika programu Swagger i wybierz pozycję Wypróbuj. Wybierz opcję Wykonaj, a zostanie zwrócona osoba, którą właśnie utworzyłeś.
Konfigurowanie projektu na potrzeby wdrażania zip
Utwórz folder
.vscode
i utwórz pliksettings.json
w folderze.Dodaj następujące polecenie, aby zignorować zmienne środowiskowe i zależności podczas wdrażania pliku zip.
{ "appService.zipIgnorePattern": ["./.env*","node_modules{,/**}"] }
Wdrażanie w usłudze Azure App Service
Aplikacja jest gotowa do wdrożenia na platformie Azure. Visual Studio Code może utworzyć usługę App Service w Azure i wdrożyć Twoją aplikację w jednym procesie.
Upewnij się, że aplikacja została zatrzymana.
Zaloguj się do platformy Azure, jeśli jeszcze tego nie zrobiono, wybierając polecenie Azure: Zaloguj się do chmury platformy Azure w palecie poleceń (Ctrl + +
W oknie Eksplorator Azure programu Visual Studio Code kliknij prawym przyciskiem myszy Usługi App Services i wybierz polecenie Utwórz nową aplikację internetową (zaawansowane).
Użyj poniższej tabeli, aby utworzyć usługę App Service:
Podpowiedź Wartość Wprowadź globalnie unikatową nazwę nowej aplikacji internetowej. Wprowadź monit, taki jak azure-sql-passwordless
. Dodaj na końcu unikatowy ciąg, taki jak123
.Wybierz grupę zasobów dla nowych zasobów. Wybierz pozycję +Utwórz nową grupę zasobów, a następnie wybierz nazwę domyślną. Wybierz stos środowiska uruchomieniowego. Wybierz wersję LTS stosu Node.js. Wybierz system operacyjny. Wybierz pozycję Linux. Wybierz lokalizację nowych zasobów. Wybierz blisko siebie lokalizację. Wybierz plan usługi App Service dla systemu Linux. Wybierz pozycję Utwórz nowy plan usługi App Service. Następnie wybierz nazwę domyślną. Wybierz warstwę cenową. Wybierz pozycję Bezpłatna (F1). Wybierz zasób usługi Application Insights dla aplikacji. Wybierz pozycję Pomiń na razie. Przed kontynuowaniem poczekaj na powiadomienie, że aplikacja została utworzona.
W eksploratorze platformy Azure rozwiń węzeł App Services i kliknij prawym przyciskiem myszy nową aplikację.
Wybierz pozycję Wdróż w aplikacji internetowej.
Wybierz folder główny projektu JavaScript.
W momencie pojawienia się okienka w Visual Studio Code wybierz Wdróż.
Po zakończeniu wdrażania aplikacja nie działa poprawnie na platformie Azure. Nadal musisz skonfigurować bezpieczne połączenie między usługą App Service i bazą danych SQL, aby pobrać dane.
Łączenie usługi App Service z usługą Azure SQL Database
Aby połączyć wystąpienie usługi App Service z usługą Azure SQL Database, wymagane są następujące kroki:
- Utwórz tożsamość zarządzaną dla usługi App Service.
- Utwórz użytkownika bazy danych SQL i skojarz ją z tożsamością zarządzaną usługi App Service.
- Przypisz role SQL do użytkownika bazy danych, który zezwala na odczyt, zapis i potencjalnie inne uprawnienia.
Dostępnych jest wiele narzędzi do implementowania następujących kroków:
Łącznik usług to narzędzie, które usprawnia uwierzytelnianie połączeń między różnymi usługami na platformie Azure. Łącznik usługi obecnie obsługuje łączenie Aplikacji App Service z bazą danych Azure SQL za pomocą interfejsu wiersza polecenia platformy Azure przy użyciu polecenia az webapp connection create sql
. To pojedyncze polecenie realizuje dla ciebie trzy kroki wymienione powyżej.
Tworzenie tożsamości zarządzanej przy użyciu Service Connector
Uruchom następujące polecenie w usłudze Cloud Shell w witrynie Azure Portal. Usługa Cloud Shell ma najnowszą wersję interfejsu wiersza polecenia platformy Azure. Zastąp zmienne własnymi <>
wartościami.
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
Weryfikowanie ustawień aplikacji usługi App Service
Zmiany wprowadzone przez Service Connector można sprawdzić w ustawieniach usługi App Service.
W programie Visual Studio Code w eksploratorze platformy Azure kliknij prawym przyciskiem myszy usługę App Service i wybierz polecenie Otwórz w portalu.
Przejdź do strony tożsamości dla usługi App Service. Na karcie Przypisane przez system status powinien być ustawiony na Włączone. Ta wartość oznacza, że tożsamość zarządzana przypisana przez system została włączona dla aplikacji.
Przejdź do strony Konfiguracja usługi App Service. Na karcie Ustawienia aplikacji powinien zostać wyświetlonych kilka zmiennych środowiskowych, które znajdowały się już w obiekcie konfiguracji mssql.
AZURE_SQL_SERVER
AZURE_SQL_DATABASE
AZURE_SQL_PORT
AZURE_SQL_AUTHENTICATIONTYPE
Nie usuwaj ani nie zmieniaj nazw właściwości ani wartości.
Testowanie wdrożonej aplikacji
Przejdź do adresu URL aplikacji, aby sprawdzić, czy połączenie z usługą Azure SQL Database działa. Adres URL aplikacji można znaleźć na stronie przeglądu usługi App Service.
Osoba utworzona lokalnie powinna być wyświetlana w przeglądarce. Gratulacje! Aplikacja jest teraz połączona z usługą Azure SQL Database zarówno w środowiskach lokalnych, jak i hostowanych.
Napiwek
Jeśli podczas testowania wystąpi błąd 500 Wewnętrzny Błąd Serwera, może być to spowodowane konfiguracją sieciową bazy danych. Sprawdź, czy serwer logiczny jest skonfigurowany z ustawieniami opisanymi w sekcji Konfigurowanie bazy danych .
Oczyszczanie zasobów
Po zakończeniu pracy z usługą Azure SQL Database usuń zasób, aby uniknąć niezamierzonych kosztów.
Na pasku wyszukiwania w witrynie Azure Portal wyszukaj ciąg Azure SQL i wybierz pasujący wynik.
Znajdź i wybierz bazę danych na liście baz danych.
Na stronie Przegląd usługi Azure SQL Database wybierz pozycję Usuń.
Na platformie Azure na pewno chcesz usunąć otwieraną stronę, wpisz nazwę bazy danych, aby potwierdzić, a następnie wybierz pozycję Usuń.
Przykładowy kod
Dostępny jest przykładowy kod dla tej aplikacji: