Dela via


Ansluta till och fråga Azure SQL Database med hjälp av Node.js och mssql npm-paket

gäller för:Azure SQL Database

Den här snabbstarten beskriver hur du ansluter ett program till en databas i Azure SQL Database och utför frågor med hjälp av Node.js och mssql. Den här snabbstarten följer den rekommenderade metoden för lösenordsfri anslutning till databasen.

Lösenordslösa anslutningar för utvecklare

Lösenordslösa anslutningar erbjuder en säkrare mekanism för åtkomst till Azure-resurser. Följande övergripande steg används för att ansluta till Azure SQL Database med lösenordslösa anslutningar i den här artikeln:

  • Förbered din miljö för lösenordsfri autentisering.
    • För en lokal miljö: Din personliga identitet används. Den här identiteten kan hämtas från en IDE, CLI eller andra lokala utvecklingsverktyg.
    • För en molnmiljö: En hanterad identitet används.
  • Autentisera i miljön med hjälp av DefaultAzureCredential från Azure Identity-biblioteket för att hämta en verifierad autentiseringsuppgift.
  • Använd verifierade autentiseringsuppgifter för att skapa Azure SDK-klientobjekt för resursåtkomst.

Du kan lära dig mer om lösenordslösa anslutningar på lösenordsfri hubb.

Förutsättningar

Konfigurera databasservern

Säkra, lösenordslösa anslutningar till Azure SQL Database kräver vissa databaskonfigurationer. Kontrollera följande inställningar på din logiska servern i Azure för att ansluta korrekt till Azure SQL Database i både lokala och värdbaserade miljöer:

  1. För lokala utvecklingsanslutningar kontrollerar du att den logiska servern är konfigurerad så att din lokala dators IP-adress och andra Azure-tjänster kan ansluta:

    • Gå till sidan Nätverk på din server.

    • Använd Valda nätverk radioknapp för att visa de ytterligare konfigurationsalternativen.

    • Välj Lägg till din klient-IPv4-adress (xx.xx.xx.xx.xx) för att lägga till en brandväggsregel som aktiverar anslutningar från din lokala IPv4-adress. Du kan också välja + Lägg till en brandväggsregel för att ange en specifik IP-adress.

    • Kontrollera att kryssrutan Tillåt Att Azure-tjänster och resurser får åtkomst till den här servern är markerad.

      En skärmbild som visar hur du konfigurerar brandväggsregler.

      Varning

      Att aktivera inställningen Tillåt Azure-tjänster och resurser att komma åt den här servern är inte en rekommenderad säkerhetspraxis för produktionsscenarier. Verkliga program bör implementera säkrare metoder, till exempel starkare brandväggsbegränsningar eller konfigurationer av virtuella nätverk.

      Du kan läsa mer om databassäkerhetskonfigurationer på följande resurser:

  2. Servern måste också ha Microsoft Entra-autentisering aktiverat och ha ett Microsoft Entra-administratörskonto tilldelat. För lokala utvecklingsanslutningar ska Microsoft Entra-administratörskontot vara ett konto som du också kan logga in på Visual Studio eller Azure CLI med lokalt. Du kan kontrollera om din server har Microsoft Entra-autentisering aktiverat på sidan Microsoft Entra-ID på den logiska servern.

    En skärmbild som visar hur du aktiverar Microsoft Entra-autentisering.

  3. Om du använder ett personligt Azure-konto kontrollerar du att du har Microsoft Entra-konfiguration och konfigurerat för Azure SQL Database för att tilldela ditt konto som serveradministratör. Om du använder ett företagskonto är Microsoft Entra-ID förmodligen redan konfigurerat åt dig.

Skapa projektet

Stegen i det här avsnittet skapar ett Node.js REST API.

  1. Skapa en ny katalog för projektet och navigera till den.

  2. Initiera projektet genom att köra följande kommando i terminalen:

    npm init -y
    
  3. Installera de nödvändiga paketen som används i exempelkoden i den här artikeln:

    npm install mssql express swagger-ui-express yamljs dotenv
    
  4. Öppna projektet i Visual Studio Code.

    code .
    
  5. Öppna filen package.json och lägg till följande egenskap och värde efter egenskapen namn för att konfigurera projektet för ESM-moduler.

    "type": "module",
    

Skapa Express.js programkod

Om du vill skapa Express.js OpenAPI-programmet skapar du flera filer:

Fil Beskrivning
.env.development Miljöfil endast för lokal utveckling.
index.js Huvudprogramfilen, som startar Express.js-appen på port 3000.
person.js Express.js /person dirigera API-filen för att hantera CRUD-åtgärder.
openapi.js Express.js /api-docs väg för OpenAPI Explorer-gränssnittet. Root omdirigerar till denna väg.
openApiSchema.yml OpenAPI 3.0-schemafil som definierar person-API.
config.js Konfigurationsfil för att läsa miljövariabler och konstruera lämpligt mssql-anslutningsobjekt.
database.js Databasklass för att hantera Azure SQL CRUD-åtgärder med hjälp av mssql npm-paketet.
./vscode/settings.json Ignorera filer med glob-mönster under utplaceringen.
  1. Skapa en index.js fil och lägg till följande 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}`);
    });
    
  2. Skapa en person.js vägfil och lägg till följande 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;
    

    För lösenordslös autentisering ändrar du param som skickas till createDatabaseConnection från SQLAuthentication till PasswordlessConfig.

    const database = await createDatabaseConnection(PasswordlessConfig);
    
  3. Skapa en openapi.js vägfil och lägg till följande kod för OpenAPI UI Explorer:

    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;
    
  4. Skapa en openApiSchema.yml fil och lägg till följande kod så att OpenAPI UI Explorer vet vilka API:er och modeller som ska visas:

    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
    

Konfigurera mssql-anslutningsobjektet

Det mssql--paketet implementerar anslutningen till Azure SQL Database genom att tillhandahålla en konfigurationsinställning för en autentiseringstyp.

  1. I Visual Studio Code skapar du en config.js-fil och lägger till följande mssql-konfigurationskod för att autentisera till 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
      }
    };
    

Skapa en lokal miljövariabelfil

Skapa en .env.development fil för dina lokala miljövariabler

Lägg till följande text och uppdatera med dina värden för <YOURSERVERNAME> och <YOURDATABASENAME>.

AZURE_SQL_SERVER=<YOURSERVERNAME>.database.windows.net
AZURE_SQL_DATABASE=<YOURDATABASENAME>
AZURE_SQL_PORT=1433
AZURE_SQL_AUTHENTICATIONTYPE=azure-active-directory-default

Notera

Lösenordslösa konfigurationsobjekt är säkra att läggas till i versionskontrollsystemet, eftersom de inte innehåller några hemligheter som användarnamn, lösenord eller åtkomstnycklar.

Lägg till koden för att ansluta till Azure SQL Database

  1. Skapa en database.js fil och lägg till följande 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;
    };
    

Testa appen lokalt

Appen är redo att testas lokalt. Kontrollera att du är inloggad på Azure Cloud i Visual Studio Code med samma konto som du angav som administratör för databasen.

  1. Kör programmet med följande kommando. Appen startar på port 3000.

    NODE_ENV=development node index.js
    

    Tabellen Person skapas i databasen när du kör det här programmet.

  2. I en webbläsare navigerar du till OpenAPI-utforskaren på http://localhost:3000.

  3. På sidan Swagger-användargränssnitt expanderar du POST-metoden och väljer Prova.

  4. Ändra JSON-exemplet så att det innehåller värden för egenskaperna. ID-egenskapen ignoreras.

    En skärmbild som visar hur du testar API:et.

  5. Välj Kör för att lägga till en ny post i databasen. API:et returnerar ett lyckat svar.

  6. Expandera metoden GET på swagger-användargränssnittssidan och välj Prova. Välj Köroch den person som du nyss skapade returneras.

Konfigurera projekt för zip-distribution

  1. Skapa en .vscode mapp och skapa en settings.json fil i mappen.

  2. Lägg till följande för att ignorera miljövariabler och beroenden under zip-distributionen.

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

Distribuera till Azure App Service

Appen är redo att distribueras till Azure. Visual Studio Code kan skapa en Azure App Service och distribuera ditt program i ett enda arbetsflöde.

  1. Kontrollera att appen har stoppats.

  2. Logga in på Azure, om du inte redan har gjort det, genom att välja kommandot Azure: Logga in på Azure Cloud i kommandopaletten (Ctrl + Skift + P)

  3. Högerklicka på noden App Services i Azure Explorer och välj Skapa ny webbapp (avancerat).

  4. Använd följande tabell för att skapa App Service:

    Snabb Värde
    Ange ett globalt unikt namn för den nya webbappen. Ange en uppmaning som azure-sql-passwordless. Lägg till en unik sträng, till exempel 123, i slutet.
    Välj en resursgrupp för nya resurser. Välj +Skapa en ny resursgrupp välj sedan standardnamnet.
    Välj en programkörningsmiljö. Välj en LTS-version av Node.js stacken.
    Välj ett operativsystem. Välj Linux.
    Välj en plats för nya resurser. Välj en plats nära dig.
    Välj en Linux App Service-plan. Välj Skapa ny App Service-plan. välj sedan standardnamnet.
    Välj en prisnivå. Välj Kostnadsfri (F1).
    Välj en Application Insights-resurs för din app. Välj Hoppa över för tillfället.
  5. Vänta tills meddelandet om att appen har skapats innan du fortsätter.

  6. I Azure Explorerexpanderar du noden App Services och högerklickar på den nya appen.

  7. Välj Distribuera till webappen.

    Skärmbild av Visual Studio Code i Azure Explorer med Distribuera till webbapp markerad.

  8. Välj rotmappen för JavaScript-projektet.

  9. När popup-fönstret Visual Studio Code visas väljer du Distribuera.

När distributionen är klar fungerar inte appen korrekt i Azure. Du måste fortfarande konfigurera den säkra anslutningen mellan App Service och SQL-databasen för att hämta dina data.

Ansluta App Service till Azure SQL Database

Följande steg krävs för att ansluta App Service-instansen till Azure SQL Database:

  1. Skapa en hanterad identitet för App Service.
  2. Skapa en SQL-databasanvändare och associera den med den hanterade App Service-identiteten.
  3. Tilldela SQL-roller till databasanvändaren som tillåter läs-, skriv- och potentiellt andra behörigheter.

Det finns flera tillgängliga verktyg för att implementera följande steg:

Service Connector är ett verktyg som effektiviserar autentiserade anslutningar mellan olika tjänster i Azure. Service Connector stöder för närvarande anslutning av en App Service till en Azure SQL-databas via Azure CLI med hjälp av kommandot az webapp connection create sql. Det här enkla kommandot slutför de tre steg som nämns ovan åt dig.

Skapa den hanterade identiteten med Service Connector

Kör följande kommando i Azure-portalens Cloud Shell. Cloud Shell har den senaste versionen av Azure CLI. Ersätt variablerna i <> med dina egna värden.

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

Verifiera App Service-appinställningarna

Du kan verifiera de ändringar som gjorts av Service Connector i App Service-inställningarna.

  1. Högerklicka på din App Service i Azure Explorer i Visual Studio Code och välj Öppna i portalen.

  2. Gå till sidan Identity för din App Service. Under fliken Systemtilldelat bör Status anges till . Det här värdet innebär att en systemtilldelad hanterad identitet har aktiverats för din app.

  3. Gå till sidan Konfiguration för din App Service. Under fliken Programinställningar bör du se flera miljövariabler, som redan fanns i konfigurationsobjektet mssql.

    • AZURE_SQL_SERVER
    • AZURE_SQL_DATABASE
    • AZURE_SQL_PORT
    • AZURE_SQL_AUTHENTICATIONTYPE

    Ta inte bort eller ändra egenskapsnamnen eller -värdena.

Testa det distribuerade programmet

Bläddra till appens URL för att testa att anslutningen till Azure SQL Database fungerar. Du kan hitta url:en för din app på översiktssidan för App Service.

Den person som du skapade lokalt bör visas i webbläsaren. Grattis! Ditt program är nu anslutet till Azure SQL Database i både lokala och värdbaserade miljöer.

Tips

Om du får ett 500 internt serverfel under testningen kan det bero på databasnätverkskonfigurationerna. Kontrollera att den logiska servern har konfigurerats med de inställningar som beskrivs i avsnittet Konfigurera databasen.

Rensa resurserna

När du är klar med arbetet med Azure SQL Database tar du bort resursen för att undvika oavsiktliga kostnader.

  1. I sökfältet i Azure-portalen söker du efter Azure SQL- och väljer matchande resultat.

  2. Leta upp och välj databasen i listan över databaser.

  3. På sidan Översikt i Azure SQL Database väljer du Ta bort.

  4. Azure är du säker på att du vill ta bort... På sidan som öppnas, skriver du namnet på din databas för att bekräfta, och väljer sedan Ta bort.

Exempelkod

Exempelkoden för det här programmet är tillgänglig:

Nästa steg