Jeg har i dag valgt at lancere det nye design af styrdindiabetes.dk.  Tag godt i mod det.

Godt nytår til jer alle.

Det er lang tid siden forrige indlæg, men der har været travlt med mange andre ting på arbejde og i fritiden.  Det er på tide at komme tilbage “on-track” med styrdindiabetes.dk.

Da jeg fornylig efter lang tids pause genoptog udvikling af styrdindiabetes.dk, virkede login med Facebook/Google/Microsoft pludselig ikke længere i Internet Explorer.  Årsagen er, at jeg i mellemtiden har opgraderet til fra Windows 8 til 8.1 med det resultat, IE er blevet opgraderet til version 11.

En spørgsmål på Mobile Services fora gav et svar fra en hjælpsom MSFT medarbejder: Jeg skulle opgradere Mobile Services JavaScript client library til nyeste version.

Mit forrige indlæg handlede om authorization via Windows Azure Mobile Services.  Authorization består af to elementer:

  1. Kun brugere, der er logget på, må kunne tilgå data.
  2. En bruger må kun kunne tilgå sit eget data.

Sidste gang diskuterede vi punkt 1 – denne gang bliver det punkt 2.

Udfordringen består i at forhindre, at en bruger læser eller redigerer i andre brugeres blodsukkermålinger.  Der er et hav af eksempler på, hvordan man sikrer, at en bruger ikke kan læse andre end sine egne data.  Det kræver blot følgende “where” clause i server-side node.js script for “Read”:

function read(query, user, request) {
    query.where({ userId: user.userId });
    request.execute();
}

Det kniber lidt mere med gode eksempler på, hvordan man f.eks. implementerer “Update” eller “Delete”.  For “Update” valgte jeg at benytte mig af det indbyggede MSSQL objekt, der kan bruges til at eksekvere rå SQL.  Som vi har talt om før, er data backend på Mobile Services blot en SQL Server:

   1:  function update(item, user, request) {
   2:      mssql.query('SELECT TOP 1 Id FROM Entries WHERE Id = ? AND userId = ?', [item.id, user.userId], {
   3:          success: function (results) {
   4:              if (results.length > 0) {
   5:                  item.userId = user.userId;
   6:                  request.execute();
   7:              }
   8:          }});
   9:  }

Idéen er, at jeg først checker, om der findes en entry med det pågældende id for den pågældende bruger.  Er det tilfældet, eksekverer jeg request’en. 

Linje 5 skal sikre, at brugeren ikke forsøger at putte en anden brugers ID på en blodsukkerregistrering.

“Delete” funktionen implementeres tilsvarende.

Vi er dermed klar til at slippe brugerne løs.  De kan logge ind med Facebook, Google eller en Microsoft konto, og de kan oprette blodsukkermålinger på livet løs uden at genere andre.

Authorization er den proces, der foregår, når man styre brugernes adgang til data.  På styrdindiabetes.dk skal det foregå på to niveauer:

  1. Kun brugere, der er logget på, må kunne tilgå data.
  2. En bruger må kun kunne tilgå sit eget data.

Det er punkt 1, vi skal se på i dette indlæg.

Vi har tidligere set på, hvordan Azure Mobile Services har authentication med Facebook o.a. indbygget.  Azure Mobile Services har også indbygget funktionalitet til at styre, hvem der må tilgå de databasetabeller, man opretter i backenden.  Det hele foregår i Azure Management portalen.

For hver tabel oprettet i Mobile Services, findes en Permissions side, hvor man kan angive, hvem der må udføre hver af de 4 CRUD operationer.  Man har følgende fire muligheder:

  • Everyone
  • Anybody with the Application Key
  • Only Authenticated Users
  • Only Scripts and Admins

image

Bemærk at for et website er der i praksis ingen forskel på “Everyone” og “Anybody with the Application Key”, da vores application key står frit tilgængelig i JavaScript’en, så enhver, der kender til højreklik og “Vis kilde” i browseren, kan få fat i nøglen.

Når en bruger via sitet forsøger at tilgå denne tabel vha. client.getTable("Entries"), vil Azure forhindre al tilgang for brugere, der ikke er logget på vha. Facebook eller andet.

I næste indlæg skal vi se på, hvordan vi sikrer, at brugerne kun kan tilgå deres eget data.

Som nævnt bruger Azure Mobile Services en SQL Server som backend database.  Det er ikke en normal SQL Server.  F.eks. findes begrebet foreign keys ikke, og Azure management konsollen giver ikke mulighed for at tilføje kolonner til tabeller som sådan.  I stedet bliver kolonner oprettet dynamisk ud fra det data, man sender til servicen.  Dette er en setting under “Configure” fanen for ens Mobile Service.

image

Husk at slå dynamic schema fra i produktion!

I første omgang har styrdindiabetes.dk behov for en enkelt tabel til at holde de indtastede blodsukkermåling.  En måling består bl.a. af en dato, typen (morgenmad, frokost, aftensmad eller sengetid) og blodsukker før og efter måltidet, hvor det giver mening.  Som JavaScript objekt kunne det se således ud i styrdindiabetes.dk (med lidt knockout.js blandet ind i det):

    var entry =
        {
            type: self.type(),
            beskrivelse: self.beskrivelse(),
            blodsukkerfoer: self.blodsukkerfoer(),
            blodsukkerefter: self.blodsukkerefter(),
            dato: dato,
            antalInsulinEnheder: self.antalInsulinEnheder(),
        };

CRUD operationer foregår vha. en REST API med POST, GET, PUT og DELETE.  Microsoft har heldigvis pakket REST API’en ind i en dejlig JavaScript API.  En CREATE/INSERT/POST operation kan f.eks. se således ud:

    client.getTable("Entries")
        .insert(entry)
        .done(function (result) {
            self.id(result.id);
            // ...
            }
        }, function (err) {
            self.root.errorMessage(err);
        });

JavaScript API’en opbygger HTTP kaldet for os.

Første gang vi laver ovenstående kald til “insert”, vil Mobile Service benytte dynamic schema og tilføje kolonner i Entries tabellen svarende til de properties, jeg definerede på entry objektet ovenfor.

Om  man kan lide dynamic schema er en smagssag.  Man kan godt frygte for integriteten i ens SQL Server database, og at der bliver givet køb på normalisering.  På den anden side øges produktiviteten betragteligt, fordi man kan koncentrere sig om at lave sin applikation og ikke om at designe database og lave datalag etc.  Jeg forestiller mig ikke, at Azure Mobile Services er beregnet til store datatunge projekter.

I næste indlæg skal vi se på, hvordan vi kan bruge login information til at styre adgang til data.

Har man et web site, der kører under https, vil requests til http typisk fejle.  Derfor er det god service overfor besøgende at omdirigere http requests til https.

Jeg faldt over nedenstående til at sætte det op på Azure Cloud Services.  Man tilføjer det til web.release.config, så reglen kun bliver brugt for release build – dvs. typisk ifm. publish til Azure i produktionsmiljø.

<configuration>
  <!-- ... -->
  <system.webServer>
    <rewrite xdt:Transform="Insert">
      <rules>
        <rule name="RedirectToHTTPS" stopProcessing="true">
          <match url="(.*)" />
          <conditions>
            <add input="{HTTPS}" pattern="off" ignoreCase="true" />
          </conditions>
          <action type="Redirect" url="https://{SERVER_NAME}/{R:1}" redirectType="Permanent" />
        </rule>
      </rules>
    </rewrite>
  </system.webServer>
</configuration>