Tässä artikkelissa näytetään miten Azure AD:lla suojattuja Funktioita kutsutaan Single Page – sovelluksesta (SPA). Tämä saattaa vaikuttaa triviaalilta, mutta oikeiden, ajantasaisten ohjeiden löytäminen saattaa osoittautua päivien tehtäväksi. Artikkeli on päivitetty 14.10.2020 vastaamaan tämän hetken tuoreinta MSALv2 – kirjastoa ja käytäntöjä.

Ratkaisun yleiskuvaus

Ratkaisussa luodaan kaksi toisiinsa linkitettyä app registrationia Azure AD:seen. Ensimmäinen tehdään Funktiolle, jossa julkaistaan API-rajapinta (expose an API). Toinen rekisteröinti tehdään single page – sovellukselle, joka käyttää edellisen julkaistua apia (use an API). Molempiin rekisteröinteihin laitetaan päälle Azure AD-kirjautuminen.

Ratkaisu on hivenen hankala hahmottaa, ja tämän lisäksi hyvin monta yksityiskohtaa on osuttava kohdalleen, jotta koko systeemi todella toimii. Paras löytämäni selitys menetelmästä löytyy sivulta Tutorial – Enable your Web Apps to sign-in users and call APIs with the Microsoft identity platform for developers. Artikkelissa kuvataan useita eri autentikoinnin käyttötilanteita, joista Call your own API – example vastaa haluamaamme tilannetta. Artikkelin ohjeita seuraten syntyy seuraavan kaltainen rakenne, joka toimii myös javascript-sovellusten käyttöön:

Kuva: SPA, funktiot ja Azure AD App Registrations.

Esimerkkikoodi

Tein pienen github repon frontend-sovelluksista, joiden avulla uskoisin pääsevän hyvin alkuun. Repo sisältää kolme erillistä esimerkkiä:

    • Sisäänkirjautuminen, eikä mitään muuta ylimääräistä.
    • Sisäänkirjautuminen ja MS Graph API:n kutsu käyttäjän nimen selvittämiseksi.
    • Sisäänkirjautuminen ja oman Azure AD suojatun funktion kutsu.

Huomaa: Tulet tarvitsemaan jonkinlaisen webbiserverin esimerkkien ajamiseen,  et voi ajaa niitä suoraan tiedostoista omalla koneellasi. Tämä johtuu siitä, että Azure AD-kirjautumisen käyttö VAATII paluun URL-osoitteen (tiedostonimet eivät käy). Tekemäni esimerkit on yksinkertaistettu Microsoftin esimerkistä MSAL.js 2.x Vanilla JavaScript Single-page Application

 

Tehtävälista

  1. Kirjoita ja julkaise funktio Azureen. Testaa sen toimivuus ennenkuin autentikointi laitetaan päälle.
  2. Konfiguroidaan funktio käyttämään Azure AD-kirjautumista, ja julkaistaan API. Ohje: Configure your Azure Functions app to use Azure AD login.
    1. Valitse advanced configuration osio linkitetystä ohjeesta.
    2. Julkaise API (Expose an API)
    3. Laita AAD-kirjautuminen päälle funktiosi app service planista.
  3. Tee toinen rekisteröinti (App Registration) SPA-sovellukselle.
    1. Ohje: Register a new application. Käytettävä menetelmä on “MSAL.js 2.0 with auth code flow”.
    2. redirect URI rekisteröinnissä:  Tämä Url-osoite (tai osoitteet) ovat sallitut osoitteet, joihin saadaan palata login-tapahtuman jälkeen. Ole tarkkana.
  4. Anna SPA:llesi oikeus kutsua funktiota.
    1. Julkaisit API:n (Exposed an API) funktion rekisteröinnissä…
    2. … nyt käytä apia (“Use API”) SPA-sovelluksen rekisteröinnissä.
  5. Laita rekisteröinnin tiedot esimerkkisovelluksiin
  6. Valmis!

Keskitytään seuraavaksi vaikeisiin osuuksiin.

Funktion App Registration ja “expose an API”

Seuraa tämän sivun ohjeita: Configure your Azure Functions app to use Azure AD login.

  • redirect uri, laita näihin täsmälleen ne arvot, mitä dokumentissa sanotaan – ei improvisointia. Korvaa osoitteen alku oman funktiosi osoitteella, loppuosa pysyy aina samana. Esimerkiksi, https://myfunctionapp.azurewebsites.net/.auth/login/aad/callback
  • Expose the API – valinta julkaisee API:n muiden sovellusten käyttöön. Huomaa erityisesti kohta “scope”! Tarvitset tätä SPA-sovelluksen rekisteröinnissä, ja myöhemmin arvo copypastetaan omaan sovelluskoodiin. Scope on koko pitkä ympyröity merkkijono, esimerkiksi,  https://myfunctionaddress/user_impersonation.

 

Expose Api

Scope Name

Kuva: Expose an Api & Scope

Alleviivattu merkkijono on kokonaisuudessaan “Scope” – https-alkuineen kaikkineen. Tarvitset tätä scopea myöhemmin SPA-rekisteröinnissä, sekä sovelluksen lähdekoodissa.

 

Rekisteröi frontend -sovellus ja anna lupa käyttää APIa

Seuraavaksi luo toinen App Registration Azure AD:seen, nyt frontend-sovellustasi varten. Seuraa aluksi näitä ohjeita: Register a new application, käytä suositeltua MSAL.js 2.0 with auth code flow – menetelmää. Tämän jälkeen frontend-sovellukseesi voisi jo sisäänkirjautua, mutta se ei vielä pysty kutsumaan ulkoisia funktioita. Korjataan asia:

Lupa kutsua Function Appia

Seuraavaksi annamme frontend sovelluksellesi luvan kutsua apia, jonka julkaisit funktion rekisteröinnin yhteydessä.

Kun olet rekisteröinyt SPA-sovelluksesi (minun SPA-sovelluksen rekisteröinti oli nimeltään CoreApp), siirry kohtaan Manage / API permissions. Täällä: + Add a permission.

1_api-permissions

Kuva: Anna lupia sovelluksellesi, Add Permission.

Etsi ja valitse luomasi function app – rekisteröinti (minulla tämä oli anothervApp). Valitse “user_impersonation” ja Add Permission. Annoit juuri luvan SPA-sovellukselle kutsua funktiota!

2-add-permission

Kuva: “user_impersonation” ja “add permission”.

Jos haluat: Grant Admin consent. Tämä tarkoittaa käytännössä sitä, sinä Administraattorina hyväksyt kaikkien käyttäjien puolesta sen, että frontend-sovellus kutsuu backend-palveluita ja välittää käyttäjätiedot kutsussa. Muutoin jokainen käyttäjä saa ensimmäisellä käyttökerralla “consent” – ilmoituksen, jossa pyydetään lupaa tähän menettelyyn.

3-grant-admin-consent

Kuva: Grant admin consent. Ei ole pakko jos ei halua.

Juhuu! Rekisteröinnit pitäisi nyt olla kohdallaan. Seuraavaksi itse sovellukset.

Esimerkkisovellukset, arvot paikoilleen.

Aluksi kloonaa sample app repo. Esimerkeissä on kolme tyypillisintä käyttötapausta: Puhdas Login, Graph API:n kutsuminen ja oman funktion kutsu. Ehdotan, että testaa ensin “plainlogin” jotta näet toimiiko sisäänkirjautuminen, vai oletko sössinyt jotain sovellusten rekisteröinnissä jo tässä vaiheessa. Jos login toimii, jatka functioncall – hakemistoon.

authConfig.js

Tässä tiedostossa konffataan paikoilleen luomasi Frontend App Registration – tiedot. Korvaa seuraavat tiedot esimerkeissä:

  • Frontend app registration clientId. Löytyy rekisteröinnin overview -sivulta, kohta Application (client) ID
  • authority, valitse:
    • Jos sallit sisäänkirjauksen millä tahansa Microsoft-tilillä (henkilökohtainen, työ, xbox, hotmail jne.), authority on  https://login.microsoftonline.com/common/
    • Jos sallit sisäänkirjauksen vain omaan AD:seen rekisteröidyille käyttäjille, authority on muotoa: https://login.microsoftonline.com/tenant_id. Oman AD:si tenant id löytyy myöskin overview – sivulta, kohdasta Directory (tenant) ID
    • redirectUri on osoite, johon palataan Microsoftin login sivujen kierroksen jälkeen. Esimerkeissä haluamme aina palata takaisin sivulle josta lähdettiin, joten esimerkkien paluuosoitteet ovat minulla seuravankaltaiset:
      • https://core.jannehansen.com/spa/plainlogin
      • https://core.jannehansen.com/spa/graphapi
      • https://core.jannehansen.com/spa/functioncall

Erityisen tärkeää! redirectUri:t täytyvät olla TÄSMÄLLEEN SAMAT kuin mitä kerroit frontend app registration – yhteydessä. Muutoin ei tule toimimaan. Käytä tietysti omia osoitteitasi, riippuen siitä minne asensit esimerkkisovellukset. Esimerkeissä siis palataan aina samalle sivulle kun mistä lähdettiin. Redirect uri voi olla myös localhost:portti – tyyppinen osoite, ja paluuosoitteita voi rekisteröidä useita samalle App Registrationille.

authRedirect.js

Tiedosto sisältää:

  • Sisäänkirjauksen ja tokeneiden hankinnan toteutukset. Merkkasin tiedoston alusta alkavan, aina vakiona pysyvän osuuden kommenteilla – sinun luultavasti ei tarvitse koskea tähän omissa toteutuksissasi.
  • graphapi esimerkissä: Kutsun MS GraphAPI:in (merkattu kommenteilla)
  • functioncall esimerkissä: Oman AD-suojatun funktion kutsu (merkattu myös kommenteilla)

Kokeillessasi plainlogin tai graphapi – esimerkkejä, luultavasti sinun ei tarvitse muuttaa mitään tässä tiedostossa – pitäisi toimia sellaisenaan.

functioncall esimerkissä,

  • ensin muuta const functionCallRequest scope niin, että se vastaa omaa scopeasi…
  • …sen jälkeen muuta funktiokutsun endpoint vastaamaan omaasi.
  • Ja riippuen siitä mitä koefunktiosi tekee, vaihtanet function callMyFunction(accessToken) – sisällön vastaamaan oman funktiosi input- ja output parametrejä. Oma esimerkkifunktioni vastasi GET pyyntöihin, parametrina oli name, jonka jälkeen funktio palautti response bodyssä “Hello [name]!”. Sinun funktio luultavasti tekee jotain ihan muuta.

 

Ongelmia? 401- Forbidden?

Melko varmasti: Olet sössinyt jotain App Registration-osuudessa. Lue ohjeet uudelleen, ja tee TÄSMÄLLEEN niinkuin on käsketty – redirect urit – clientid, tenant, scope jne.

 

Siinäpä se oli. Teoriassa sinun pitäisi nyt pystyä kutsua AAD-suojattuja funktioitasi. Kuten näit, hyvin monta yksityiskohtaa on osuttava täsmälleen kohdalleen, että himmeli toimii. Näillä ohjeilla homman voi parhaimmillaan saada toimimaan vajaassa tunnissa.

Ohje toimii ainakin nyt 14.10.2020 kirjoitushetkellä, ja toistaiseksi. Ole ystävällinen ja ilmoita minulle kun se ei enää toimikaan. Siihen asti – pidä hauskaa!