Kurz: Přidání ověřování a oprávnění do aplikace při použití azure Web PubSub

V části Vytvoření chatovací aplikace jste zjistili, jak pomocí rozhraní WebSocket API odesílat a přijímat data pomocí azure Web PubSub. Všimněte si, že kvůli jednoduchosti nevyžaduje žádné ověřování. I když Azure Web PubSub vyžaduje připojení přístupového tokenu, negotiate rozhraní API použité v kurzu k vygenerování přístupového tokenu nepotřebuje ověřování. Toto rozhraní API může volat kdokoli, aby získal přístupový token.

V reálné aplikaci obvykle chcete, aby se uživatel nejdřív přihlásil, než bude moct aplikaci používat. V tomto kurzu se dozvíte, jak integrovat Web PubSub s ověřovacím a autorizačním systémem vaší aplikace, aby byl bezpečnější.

Kompletní ukázku kódu tohoto kurzu najdete na GitHubu.

V tomto kurzu se naučíte:

  • Povolení ověřování GitHubu
  • Přidání middlewaru ověřování do aplikace
  • Přidání oprávnění klientům

Přidání ověřování do aplikace chatovací místnosti

Tento kurz znovu použije chatovací aplikaci vytvořenou v aplikaci Pro sestavení chatu. Kompletní ukázku kódu pro chatovací aplikaci můžete také naklonovat z GitHubu.

V tomto kurzu přidáte do chatovací aplikace ověřování a integrujete ji s web pubSub.

Nejprve do chatovací místnosti přidejte ověřování GitHubu, aby se uživatel mohl přihlásit pomocí účtu GitHubu.

  1. Nainstalujte závislosti.

    npm install --save cookie-parser
    npm install --save express-session
    npm install --save passport
    npm install --save passport-github2
    
  2. server.js Vyhledejte soubor v adresáři a povolte ověřování GitHubu přidáním následujícího kódu doserver.js:

    const app = express();
    
    const users = {};
    passport.use(
      new GitHubStrategy({
        clientID: process.argv[3],
        clientSecret: process.argv[4]
      },
      (accessToken, refreshToken, profile, done) => {
        users[profile.id] = profile;
        return done(null, profile);
      }
    ));
    
    passport.serializeUser((user, done) => {
      done(null, user.id);
    });
    
    passport.deserializeUser((id, done) => {
      if (users[id]) return done(null, users[id]);
      return done(`invalid user id: ${id}`);
    });
    
    app.use(cookieParser());
    app.use(session({
      resave: false,
      saveUninitialized: true,
      secret: 'keyboard cat'
    }));
    app.use(passport.initialize());
    app.use(passport.session());
    app.get('/auth/github', passport.authenticate('github', { scope: ['user:email'] }));
    app.get('/auth/github/callback', passport.authenticate('github', { successRedirect: '/' }));
    

    Předchozí kód používá Passport.js k povolení ověřování GitHubu. Tady je jednoduchý obrázek toho, jak funguje:

    1. /auth/github se přesměruje na github.com pro přihlášení.
    2. Jakmile se přihlásíte, GitHub vás přesměruje na kód, na /auth/github/callback který vaše aplikace dokončí ověřování. (Pokud chcete zjistit, jak je profil vrácený z GitHubu ověřený a trvalý na serveru, podívejte se na ověřené zpětné volání v passport.use()souboru .)
    3. Po dokončení ověřování budete přesměrováni na domovskou stránku (/) webu.

    Další podrobnosti o GitHub OAuth a Passport.js najdete v následujících článcích:

    K otestování je potřeba nejprve vytvořit aplikaci GitHub OAuth:

    1. Přejděte na https://www.github.com, otevřete svůj profil a vyberte Nastavení> NastaveníDeveloper.
    2. Přejděte do aplikací OAuth a vyberte Nová aplikace OAuth.
    3. Vyplňte název aplikace a adresu URL domovské stránky (adresa URL může být cokoli, co se vám líbí) a nastavte adresu URL zpětného volání autorizace na http://localhost:8080/auth/github/callbackhodnotu . Tato adresa URL odpovídá rozhraní API zpětného volání, které jste odhalili na serveru.
    4. Po registraci aplikace zkopírujte ID klienta a vyberte Vygenerovat nový tajný klíč klienta.

    Spuštěním následujícího příkazu otestujte nastavení, nezapomeňte nahradit <connection-string><client-id>, a <client-secret> s vašimi hodnotami.

    export WebPubSubConnectionString="<connection-string>"
    export GitHubClientId="<client-id>"
    export GitHubClientSecret="<client-secret>"
    node server
    

    Nyní otevřete http://localhost:8080/auth/github. Budete přesměrováni na GitHub, abyste se mohli přihlásit. Po přihlášení budete přesměrováni do chatovací aplikace.

  3. Aktualizujte chatovací místnost tak, aby používala identitu, kterou získáte z GitHubu, místo výzvy uživatele k zadání uživatelského jména.

    Umožňuje aktualizovat public/index.html přímé volání /negotiate bez předání ID uživatele.

    let messages = document.querySelector('#messages');
    let res = await fetch(`/negotiate`);
    if (res.status === 401) {
      let m = document.createElement('p');
      m.innerHTML = 'Not authorized, click <a href="/auth/github">here</a> to login';
      messages.append(m);
      return;
    }
    let data = await res.json();
    let ws = new WebSocket(data.url);
    

    Když je uživatel přihlášený, požadavek automaticky přenese identitu uživatele prostřednictvím souboru cookie. Stačí zkontrolovat, jestli uživatel v objektu req existuje, a přidat uživatelské jméno do přístupového tokenu Web PubSub:

    app.get('/negotiate', async (req, res) => {
      if (!req.user || !req.user.username) {
        res.status(401).send('missing user id');
        return;
      }
      let options = {
        userId: req.user.username
      };
      let token = await serviceClient.getClientAccessToken(options);
      res.json({
        url: token.url
      });
    });
    

    Teď znovu spusťte server a při prvním otevření chatovací místnosti se zobrazí zpráva , že není autorizovaný. Vyberte přihlašovací odkaz, který chcete přihlásit, a pak uvidíte, že funguje jako předtím.

Práce s oprávněními

V předchozích kurzech jste se naučili používat WebSocket.send() přímé publikování zpráv do jiných klientů pomocí subprotocolu. Ve skutečné aplikaci možná nebudete chtít, aby klient mohl publikovat nebo přihlásit k odběru jakékoli skupiny bez řízení oprávnění. V této části se dozvíte, jak řídit klienty pomocí systému oprávnění web pubSub.

V podsítě Web PubSub může klient provádět následující typy operací s dílčím souhrnem:

  • Odesílání událostí na server
  • Publikování zpráv do skupiny
  • Připojte se (přihlaste se k odběru) skupiny.

Odeslání události na server je výchozí operací klienta. Nepoužívá se žádný protokol, takže je vždy povolený. Pokud chcete publikovat a přihlásit se k odběru skupiny, klient musí získat oprávnění. Server může udělit oprávnění klientům dvěma způsoby:

  • Určete role, když je klient připojený (role představuje koncept představující počáteční oprávnění při připojení klienta).
  • Pomocí rozhraní API udělte klientovi oprávnění po připojení.

Aby se klient mohl ke skupině připojit, musí se ke skupině připojit pomocí zprávy "Join group" (Skupina připojení), jakmile získá oprávnění. Případně může server použít rozhraní API k přidání klienta do skupiny, i když nemá oprávnění k připojení.

Teď použijeme tento systém oprávnění k přidání nové funkce do chatovací místnosti. Do chatovací místnosti přidáte nový typ uživatele s názvem správce . Správci povolíte odesílat systémové zprávy (zprávy začínající na "[SYSTEM]") přímo z klienta.

Nejprve je potřeba oddělit systémové a uživatelské zprávy do dvou různých skupin, abyste mohli řídit svá oprávnění samostatně.

Změna server.js pro odesílání různých zpráv do různých skupin:

let handler = new WebPubSubEventHandler(hubName, {
  path: '/eventhandler',
  handleConnect: (req, res) => {
    res.success({
      groups: ['system', 'message'],
    });
  },
  onConnected: req => {
    console.log(`${req.context.userId} connected`);
    serviceClient.group('system').sendToAll(`${req.context.userId} joined`, { contentType: 'text/plain' });
  },
  handleUserEvent: (req, res) => {
    if (req.context.eventName === 'message') {
      serviceClient.group('message').sendToAll({
        user: req.context.userId,
        message: req.data
      });
    }
    res.success();
  }
});

Předchozí kód používá WebPubSubServiceClient.group().sendToAll() k odeslání zprávy do skupiny místo centra.

Protože se teď zpráva odesílá do skupin, musíte do skupin přidat klienty, aby mohli dál přijímat zprávy. Obslužnou rutinu handleConnect použijte k přidání klientů do skupin.

Poznámka:

handleConnect se aktivuje, když se klient pokouší připojit k podsítě Web PubSub. V této obslužné rutině můžete vrátit skupiny a role, takže služba může přidat připojení ke skupinám nebo udělit role, jakmile se připojení vytvoří. Služba může také použít res.fail() k odepření připojení.

Pokud chcete aktivovat handleConnect, přejděte na webu Azure Portal do nastavení obslužné rutiny události a vyberte připojit se v systémových událostech.

Musíte také aktualizovat kód HTML klienta, protože teď server odesílá zprávy JSON místo prostého textu:

let ws = new WebSocket(data.url, 'json.webpubsub.azure.v1');
ws.onopen = () => console.log('connected');

ws.onmessage = event => {
  let m = document.createElement('p');
  let message = JSON.parse(event.data);
  switch (message.type) {
    case 'message':
      if (message.group === 'system') m.innerText = `[SYSTEM] ${message.data}`;
      else if (message.group === 'message') m.innerText = `[${message.data.user}] ${message.data.message}`;
      break;
  }
  messages.appendChild(m);
};

let message = document.querySelector('#message');
message.addEventListener('keypress', e => {
  if (e.charCode !== 13) return;
  ws.send(JSON.stringify({
    type: 'event',
    event: 'message',
    dataType: 'text',
    data: message.value
  }));
  message.value = '';
});

Potom změňte kód klienta tak, aby se odeslal systémové skupině, když uživatelé vyberou systémovou zprávu:

<button id="system">system message</button>
...
<script>
  (async function() {
    ...
    let system = document.querySelector('#system');
    system.addEventListener('click', e => {
      ws.send(JSON.stringify({
        type: 'sendToGroup',
        group: 'system',
        dataType: 'text',
        data: message.value
      }));
      message.value = '';
    });
  })();
</script>

Ve výchozím nastavení nemá klient oprávnění k odesílání do žádné skupiny. Aktualizujte kód serveru tak, aby uživateli s právy správce udělil oprávnění (pro jednoduchost je ID správce poskytováno jako argument příkazového řádku).

app.get('/negotiate', async (req, res) => {
  ...
  if (req.user.username === process.argv[2]) options.claims = { role: ['webpubsub.sendToGroup.system'] };
  let token = await serviceClient.getClientAccessToken(options);
});

Nyní spusťte node server <admin-id>. Vidíte, že můžete odeslat systémovou zprávu každému klientovi, když se přihlásíte jako <admin-id>.

Pokud se ale přihlásíte jako jiný uživatel, při výběru systémové zprávy se nic nestane. Můžete očekávat, že služba zobrazí chybu, abyste věděli, že operace není povolená. Pokud chcete poskytnout tuto zpětnou vazbu, můžete ji nastavit ackId při publikování zprávy. Při každém ackId zadání vrátí web pubSub zprávu s odpovídajícími informacemi ackId o tom, jestli operace proběhla úspěšně nebo ne.

Změňte kód odeslání systémové zprávy na následující kód:

let ackId = 0;
system.addEventListener('click', e => {
  ws.send(JSON.stringify({
    type: 'sendToGroup',
    group: 'system',
    ackId: ++ackId,
    dataType: 'text',
    data: message.value
    }));
  message.value = '';
});

Změňte také kód zpracování zpráv tak, aby zpracovával ack zprávu:

ws.onmessage = event => {
  ...
  switch (message.type) {
    case 'ack':
      if (!message.success && message.error.name === 'Forbidden') m.innerText = 'No permission to send system message';
      break;
  }
};

Teď znovu spusťte server a přihlaste se jako jiný uživatel. Při pokusu o odeslání systémové zprávy se zobrazí chybová zpráva.

Kompletní ukázka kódu tohoto kurzu najdete na GitHubu.

Další kroky

V tomto kurzu získáte základní představu o tom, jak se připojit ke službě Web PubSub a jak publikovat zprávy do připojených klientů pomocí subprotocolu.

Další informace o používání služby Web PubSub najdete v dalších kurzech dostupných v dokumentaci.