Aggiungere l'accesso a un'app Web Node.jsAdd sign-in to a Node.js web app

Nota

Non tutti gli scenari e le funzionalità di Azure Active Directory usano l'endpoint v2.0.Not all Azure Active Directory scenarios and features work with the v2.0 endpoint. Per determinare se è necessario usare l'endpoint v2.0 o l'endpoint v1.0, leggere le informazioni sulle limitazioni della versione 2.0.To determine whether you should use the v2.0 endpoint or the v1.0 endpoint, read about v2.0 limitations.

In questa esercitazione si userà Passport per eseguire le operazioni seguenti:In this tutorial, we use Passport to do the following tasks:

  • In un'app Web, consentire l'accesso dell'utente con Azure Active Directory (Azure AD) e l'endpoint 2.0.In a web app, sign in the user by using Azure Active Directory (Azure AD) and the v2.0 endpoint.
  • Visualizzare informazioni relative all'utente.Display information about the user.
  • Disconnettere l'utente dall'app.Sign the user out of the app.

Passport è il middleware di autenticazione per Node.js.Passport is authentication middleware for Node.js. Passport, flessibile e modulare, può essere rilasciato in modo non invadente in qualsiasi applicazione Web basata su Express o Restify.Flexible and modular, Passport can be unobtrusively dropped into any Express-based or restify web application. In Passport una gamma completa di strategie supporta l'autenticazione usando un nome utente e password, Facebook, Twitter o altre opzioni.In Passport, a comprehensive set of strategies support authentication by using a username and password, Facebook, Twitter, or other options. È stata sviluppata una strategia per Azure AD.We have developed a strategy for Azure AD. Questo articolo illustra come installare il modulo e quindi aggiungere il plug-in passport-azure-ad di Azure AD.In this article, we show you how to install the module, and then add the Azure AD passport-azure-ad plug-in.

ScaricareDownload

Il codice per questa esercitazione è salvato su GitHub.The code for this tutorial is maintained on GitHub. Per seguire l'esercitazione, è possibile scaricare la struttura dell'app come file con estensione zip o clonare la struttura:To follow the tutorial, you can download the app's skeleton as a .zip file or clone the skeleton:

git clone --branch skeleton https://github.com/AzureADQuickStarts/AppModelv2-WebApp-OpenIDConnect-nodejs.git

Al termine dell'esercitazione, è anche possibile ottenere l'applicazione completata.You also can get the completed application at the end of this tutorial.

1: Registrare un'app1: Register an app

Per registrare un'app creare una nuova app in apps.dev.microsoft.com o seguire questa procedura dettagliata.Create a new app at apps.dev.microsoft.com, or follow these detailed steps to register an app. Assicurarsi di:Make sure you:

  • Copiare l'ID applicazione assegnato all'app.Copy the Application Id assigned to your app. È necessario per eseguire questa esercitazione.You need it for this tutorial.
  • Aggiungere la piattaforma Web per l'app.Add the Web platform for your app.
  • Copiare l' URI di reindirizzamento dal portale.Copy the Redirect URI from the portal. È necessario usare il valore URI predefinito urn:ietf:wg:oauth:2.0:oob.You must use the default URI value of urn:ietf:wg:oauth:2.0:oob.

2: Aggiungere prerequisiti alla directory2: Add prerequisities to your directory

Al prompt dei comandi passare alla cartella radice, se necessario.At a command prompt, change directories to go to your root folder, if you are not already there. Eseguire i comandi seguenti:Run the following commands:

  • npm install express
  • npm install ejs
  • npm install ejs-locals
  • npm install restify
  • npm install mongoose
  • npm install bunyan
  • npm install assert-plus
  • npm install passport
  • npm install webfinger
  • npm install body-parser
  • npm install express-session
  • npm install cookie-parser

Nella struttura di avvio rapido si usa anche passport-azure-ad:In addition, we use passport-azure-ad in the skeleton of the quickstart:

  • npm install passport-azure-ad

In questo modo, vengono installate le librerie usate da passport-azure-ad.This installs the libraries that passport-azure-ad uses.

3: Configurare l'app per l'uso della strategia passport-node-js3: Set up your app to use the passport-node-js strategy

Configurare il middleware Express per l'uso del protocollo di autenticazione OpenID Connect.Set up the Express middleware to use the OpenID Connect authentication protocol. Passport verrà usato, tra le altre cose, per inviare richieste di accesso e disconnessione, gestire la sessione utente e ottenere informazioni sull'utente.You use Passport to issue sign-in and sign-out requests, manage the user's session, and get information about the user, among other things.

  1. Nella radice del progetto aprire il file Config.js.In the root of the project, open the Config.js file. Nella sezione exports.creds immettere i valori di configurazione dell'app.In the exports.creds section, enter your app's configuration values.

    • clientID: l'ID applicazione assegnato all'app nel portale di Azure.clientID: The Application Id that's assigned to your app in the Azure portal.
    • returnURL: l'URI di reindirizzamento immesso nel portale.returnURL: The Redirect URI that you entered in the portal.
    • clientSecret: il segreto generato nel portale.clientSecret: The secret that you generated in the portal.
  2. Nella radice del progetto aprire il file App.js.In the root of the project, open the App.js file. Per richiamare la strategia OIDCStrategy, fornita con passport-azure-ad, aggiungere la chiamata seguente:To invoke the OIDCStrategy stratey, which comes with passport-azure-ad, add the following call:

    var OIDCStrategy = require('passport-azure-ad').OIDCStrategy;
    
    // Add some logging
    var log = bunyan.createLogger({
      name: 'Microsoft OIDC Example Web Application'
    });
    
  3. Per gestire le richieste di accesso usare la strategia a cui si è appena fatto riferimento:To handle your sign-in requests, use the strategy you just referenced:

    // Use the OIDCStrategy within Passport (section 2)
    //
    //   Strategies in Passport require a `validate` function. The function accepts
    //   credentials (in this case, an OpenID identifier), and invokes a callback
    //   with a user object.
    passport.use( new OIDCStrategy({
      callbackURL: config.creds.returnURL,
      realm: config.creds.realm,
      clientID: config.creds.clientID,
      clientSecret: config.creds.clientSecret,
      oidcIssuer: config.creds.issuer,
      identityMetadata: config.creds.identityMetadata,
      responseType: config.creds.responseType,
      responseMode: config.creds.responseMode,
      skipUserProfile: config.creds.skipUserProfile
      scope: config.creds.scope
    },
    function(iss, sub, profile, accessToken, refreshToken, done) {
      log.info('Example: Email address we received was: ', profile.email);
      // Asynchronous verification, for effect...
      process.nextTick(function () {
        findByEmail(profile.email, function(err, user) {
          if (err) {
            return done(err);
          }
          if (!user) {
            // "Auto-registration"
            users.push(profile);
            return done(null, profile);
          }
          return done(null, user);
        });
      });
    }
    ));
    

Passport usa un modello simile per tutte le strategie (Twitter, Facebook e così via).Passport uses a similar pattern for all its strategies (Twitter, Facebook, and so on). Tutti i writer di strategie rispettano questo modello.All strategy writers adhere to the pattern. Passare alla strategia un elemento function() che usa un token e done come parametri.Pass the strategy a function() that uses a token and done as parameters. La strategia viene restituita dopo l'esecuzione di tutte le operazioni.The strategy is returned after it does all its work. Archiviare l'utente e mettere da parte il token per non doverlo richiedere nuovamente.Store the user and stash the token so you don’t need to ask for it again.

Importante

Il codice precedente accetta qualsiasi utente che può eseguire l'autenticazione al server.The preceding code takes any user that can authenticate to your server. Questa operazione è nota come registrazione automatica.This is known as auto-registration. Nei server di produzione è preferibile non consentire l'accesso a chiunque senza prima prevedere un processo di registrazione a scelta.On a production server, you wouldn’t want to let anyone in without first having them go through a registration process that you choose. Questo è il criterio solitamente adottato per le app consumer.This is usually the pattern that you see in consumer apps. L'app potrebbe consentire di eseguire la registrazione con Facebook, ma poi richiede di inserire informazioni aggiuntive.The app might allow you to register with Facebook, but then it asks you to enter additional information. Se per questa esercitazione non è stato usato un programma della riga di comando, è possibile estrarre il messaggio di posta elettronica dall'oggetto token restituito.If you weren't using a command-line program for this tutorial, you could extract the email from the token object that is returned. Quindi, è possibile chiedere all'utente di inserire informazioni aggiuntive.Then, you might ask the user to enter additional information. Trattandosi di un server di test, è possibile aggiungere l'utente direttamente al database in-memory.Because this is a test server, you add the user directly to the in-memory database.

  1. Aggiungere i metodi che consentono di tenere traccia degli utenti che hanno eseguito l'accesso, come richiesto da Passport.Add the methods that you use to keep track of users who are signed in, as required by Passport. Questa operazione include la serializzazione e deserializzazione delle informazioni dell'utente:This includes serializing and deserializing the user's information:

    
    // Passport session setup (section 2)
    
    //   To support persistent login sessions, Passport needs to be able to
    //   serialize users into, and deserialize users out of, the session. Typically,
    //   this is as simple as storing the user ID when serializing, and finding
    //   the user by ID when deserializing.
    passport.serializeUser(function(user, done) {
    done(null, user.email);
    });
    
    passport.deserializeUser(function(id, done) {
    findByEmail(id, function (err, user) {
      done(err, user);
    });
    });
    
    // Array to hold signed-in users
    var users = [];
    
    var findByEmail = function(email, fn) {
    for (var i = 0, len = users.length; i < len; i++) {
      var user = users[i];
      log.info('we are using user: ', user);
      if (user.email === email) {
        return fn(null, user);
      }
    }
    return fn(null, null);
    };
    
  2. Aggiungere il codice che carica il motore di Express.Add the code that loads the Express engine. Verranno usati i modelli /views e /routes predefiniti forniti da Express:You use the default /views and /routes pattern that Express provides:

    
    // Set up Express (section 2)
    
    var app = express();
    
    app.configure(function() {
    app.set('views', __dirname + '/views');
    app.set('view engine', 'ejs');
    app.use(express.logger());
    app.use(express.methodOverride());
    app.use(cookieParser());
    app.use(expressSession({ secret: 'keyboard cat', resave: true, saveUninitialized: false }));
    app.use(bodyParser.urlencoded({ extended : true }));
    // Initialize Passport!  Also use passport.session() middleware, to support
    // persistent login sessions (recommended).
    app.use(passport.initialize());
    app.use(passport.session());
    app.use(app.router);
    app.use(express.static(__dirname + '/../../public'));
    });
    
  3. Aggiungere le route POST che trasferiscono le richieste di accesso effettive al motore passport-azure-ad:Add the POST routes that hand off the actual sign-in requests to the passport-azure-ad engine:

    
    // Auth routes (section 3)
    
    // GET /auth/openid
    //   Use passport.authenticate() as route middleware to authenticate the
    //   request. The first step in OpenID authentication involves redirecting
    //   the user to the user's OpenID provider. After authenticating, the OpenID
    //   provider redirects the user back to this application at
    //   /auth/openid/return.
    
    app.get('/auth/openid',
    passport.authenticate('azuread-openidconnect', { failureRedirect: '/login' }),
    function(req, res) {
      log.info('Authentication was called in the sample');
      res.redirect('/');
    });
    
    // GET /auth/openid/return
    //   Use passport.authenticate() as route middleware to authenticate the
    //   request. If authentication fails, the user is redirected back to the
    //   sign-in page. Otherwise, the primary route function is called.
    //   In this example, it redirects the user to the home page.
    app.get('/auth/openid/return',
    passport.authenticate('azuread-openidconnect', { failureRedirect: '/login' }),
    function(req, res) {
    
      res.redirect('/');
    });
    
    // POST /auth/openid/return
    //   Use passport.authenticate() as route middleware to authenticate the
    //   request. If authentication fails, the user is redirected back to the
    //   sign-in page. Otherwise, the primary route function is called. 
    //   In this example, it redirects the user to the home page.
    
    app.post('/auth/openid/return',
    passport.authenticate('azuread-openidconnect', { failureRedirect: '/login' }),
    function(req, res) {
    
      res.redirect('/');
    });
    

4: Usare Passport per inviare le richieste di accesso e disconnessione ad Azure AD4: Use Passport to issue sign-in and sign-out requests to Azure AD

L'app è configurata ora per comunicare con l'endpoint 2.0 mediante il protocollo di autenticazione OpenID Connect.Your app is now set up to communicate with the v2.0 endpoint by using the OpenID Connect authentication protocol. La strategia passport-azure-ad gestisce tutti i dettagli relativi alla creazione dei messaggi di autenticazione, alla convalida dei token da Azure AD e alla gestione della sessione utente.The passport-azure-ad strategy takes care of all the details of crafting authentication messages, validating tokens from Azure AD, and maintaining the user session. A questo punto, è sufficiente offrire agli utenti un modo per accedere e disconnettersi e per raccogliere informazioni aggiuntive sull'utente connesso.All that is left to do is to give your users a way to sign in and sign out, and to gather more information about the user who is signed in.

  1. Aggiungere al file App.js i metodi default, login, account e logout:Add the default, login, account, and logout methods to your App.js file:

    
    //Routes (section 4)
    
    app.get('/', function(req, res){
    res.render('index', { user: req.user });
    });
    
    app.get('/account', ensureAuthenticated, function(req, res){
    res.render('account', { user: req.user });
    });
    
    app.get('/login',
    passport.authenticate('azuread-openidconnect', { failureRedirect: '/login' }),
    function(req, res) {
      log.info('Login was called in the sample');
      res.redirect('/');
    });
    
    app.get('/logout', function(req, res){
    req.logout();
    res.redirect('/');
    });
    

    Di seguito sono riportati i dettagli:Here are the details:

    • La route / reindirizza alla vista index.ejs eThe / route redirects to the index.ejs view. passa l'utente nella richiesta (se esistente).It passes the user in the request (if it exists).
    • La route /account prima verifica che l'utente sia autenticato (questo passaggio viene implementato nel codice seguente)The /account route first ensures that you are authenticated (you implement that in the following code). e quindi passa l'utente nella richiesta.Then, it passes the user in the request. In questo modo è possibile ottenere altre informazioni sull'utente.This is so you can get more information about the user.
    • La route /login chiama l'autenticatore azuread-openidconnect da passport-azuread.The /login route calls your azuread-openidconnect authenticator from passport-azuread. Se l'operazione ha esito negativo, reindirizza di nuovo l'utente a /login.If that doesn't succeed, it redirects the user back to /login.
    • La route /logout chiama la vista logout.ejs (e route).The /logout route calls the logout.ejs view (and route). I cookie vengono cancellati e quindi l'utente torna a index.ejs.This clears cookies, and then returns the user back to index.ejs.
  2. Aggiungere il metodo EnsureAuthenticated usato in precedenza in /account:Add the EnsureAuthenticated method that you used earlier in /account:

    
    // Route middleware to ensure the user is authenticated (section 4)
    
    //   Use this route middleware on any resource that needs to be protected. If
    //   the request is authenticated (typically via a persistent login session),
    //   the request proceeds. Otherwise, the user is redirected to the
    //   sign-in page.
    function ensureAuthenticated(req, res, next) {
    if (req.isAuthenticated()) { return next(); }
    res.redirect('/login')
    }
    
  3. In App.js creare il server:In App.js, create the server:

    
    app.listen(3000);
    

5: Creare le viste e le route in Express per visualizzare l'utente nel sito Web5: Create the views and routes in Express that you show your user on the website

Aggiungere le route e le viste che mostrano informazioni all'utente.Add the routes and views that show information to the user. Le route e le viste gestiscono anche le route /logout e /login precedentemente create.The routes and views also handle the /logout and /login routes that you created.

  1. Nella directory radice creare la route /routes/index.js.In the root directory, create the /routes/index.js route.

    
    /*
    * GET home page.
    */
    
    exports.index = function(req, res){
     res.render('index', { title: 'Express' });
    };
    
  2. Nella directory radice creare la route /routes/user.js.In the root directory, create the /routes/user.js route.

    
    /*
    * GET users listing.
    */
    
    exports.list = function(req, res){
    res.send("respond with a resource");
    };
    

    /routes/index.js e /routes/user.js sono semplici route che passeranno la richiesta alle viste, incluso l'utente se presente./routes/index.js and /routes/user.js are simple routes that pass along the request to your views, including the user, if present.

  3. Nella directory radice creare la vista /views/index.ejs.In the root directory, create the /views/index.ejs view. Questa pagina chiama i metodi login e logout.This page calls your login and logout methods. È possibile anche usare la vista /views/index.ejs per acquisire informazioni sull'account.You also use the /views/index.ejs view to capture account information. È possibile usare l'espressione if (!user) condizionale quando l'utente viene passato nella richiesta,You can use the conditional if (!user) as the user being passed through in the request. a prova che l'utente ha eseguito l'accesso.It is evidence that you have a user signed in.

    <% if (!user) { %>
      <h2>Welcome! Please sign in.</h2>
      <a href="/login">Sign in</a>
    <% } else { %>
      <h2>Hello, <%= user.displayName %>.</h2>
      <a href="/account">Account info</a></br>
      <a href="/logout">Sign out</a>
    <% } %>
    
  4. Nella directory radice creare la vista /views/account.ejs.In the root directory, create the /views/account.ejs view. La vista /views/account.ejs consente di visualizzare informazioni aggiuntive che passport-azuread inserisce nella richiesta dell'utente.The /views/account.ejs view allows you to view additional information that passport-azuread puts in the user request.

    <% if (!user) { %>
      <h2>Welcome! Please sign in.</h2>
      <a href="/login">Sign in</a>
    <% } else { %>
    <p>displayName: <%= user.displayName %></p>
    <p>givenName: <%= user.name.givenName %></p>
    <p>familyName: <%= user.name.familyName %></p>
    <p>UPN: <%= user._json.upn %></p>
    <p>Profile ID: <%= user.id %></p>
    <p>Full Claimes</p>
    <%- JSON.stringify(user) %>
    <p></p>
    <a href="/logout">Sign out</a>
    <% } %>
    
  5. Aggiungere un layout.Add a layout. Nella directory radice creare la vista /views/layout.ejs.In the root directory, create the /views/layout.ejs view.

    
    <!DOCTYPE html>
    <html>
      <head>
          <title>Passport-OpenID Example</title>
      </head>
      <body>
          <% if (!user) { %>
              <p>
              <a href="/">Home</a> |
              <a href="/login">Sign in</a>
              </p>
          <% } else { %>
              <p>
              <a href="/">Home</a> |
              <a href="/account">Account</a> |
              <a href="/logout">Sign out</a>
              </p>
          <% } %>
          <%- body %>
      </body>
    </html>
    
  6. Per compilare ed eseguire l'app, eseguire node app.jsTo build and run your app, run node app.js. e quindi passare a http://localhost:3000.Then, go to http://localhost:3000.

  7. Accedere con un account Microsoft personale o con un account aziendale o dell'istituto di istruzione.Sign in with either a personal Microsoft account or a work or school account. Osservare come l'identità dell'utente sia riflessa nell'elenco /account.Note that the user's identity is reflected in the /account list.

Si dispone ora di un'app Web protetta tramite protocolli standard del settore.You now have a web app that is secured by using industry standard protocols. È possibile autenticare gli utenti nell'app usando i relativi account personali e aziendali o dell'istituto di istruzione.You can authenticate users in your app by using their personal and work or school accounts.

Passaggi successiviNext steps

Come riferimento viene fornito l'esempio completato, senza i valori di configurazione, come file zip.For reference, the completed sample (without your configuration values) is provided as a .zip file. È anche possibile clonarlo da GitHub:You also can clone it from GitHub:

git clone --branch complete https://github.com/AzureADQuickStarts/AppModelv2-WebApp-OpenIDConnect-nodejs.git

È possibile ora passare ad argomenti più avanzati.Next, you can move on to more advanced topics. È consigliabile provare:You might want to try:

Proteggere un'API Web Node.js usando l'endpoint 2.0Secure a Node.js web API by using the v2.0 endpoint

Altre risorse:Here are some additional resources:

Ottenere aggiornamenti della sicurezza per i prodottiGet security updates for our products

È consigliabile eseguire l'iscrizione per ricevere una notifica quando si verificano problemi di protezione.We encourage you to sign up to be notified when security incidents occur. Nella pagina Notifiche sulla sicurezza Microsoft effettuare la sottoscrizione agli advisory sulla sicurezza.On the Microsoft Technical Security Notifications page, subscribe to Security Advisories Alerts.