Login med JWT

By . Latest revision .

Vi har i tidigare kurser och i andra programmeringsspråk hanterat inloggning med hjälp av sessioner. I denna övning ska vi titta på ett sätt att autentisera våra klienter mot servern utan sessioner. Detta ger oss vissa fördelar som att vi har inbyggda utlöpstider och att det underlättar om vi vill skala upp vårt API, samtidigt som det ger ett säkert sätt att identifiera klienterna på.

I denna övning tittar vi på hur vi med hjälp av Postman registrerar en användare, loggar in som denna användare och får en JSON Web Token (JWT). Sist i övningen tittar vi på hur vi med hjälp av JWT och mithril kommer åt funktioner i Lager API:t som ligger skyddade.

#Registrering och inloggning

Vi börjar med att registrera en användare i Lager API:t genom att skicka en POST till URL’en /v2/auth/register med 3 parametrar i body: api_key, email och password. Detta kan till exempel göras med Postman eller som en POST request från JavaScript.

Vi får följande svar från Lager API:t:

{
    "data": {
        "message": "User successfully registered."
    }
}

När vi sedan vill logga in som den nyss registrerade användaren gör vi det genom att skicka en POST till URL’en /v2/auth/login med de samma 3 parametrar i body: api_key, email och password.

Vi får följande svar från Lager API:t. token i det nedanstående data objektet är den JSON web token vi har fått tillbaka från API:t.

{
    "data": {
        "type": "success",
        "message": "User logged in",
        "user": {
            "api_key": "...",
            "email": "new@example.com"
        },
        "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhc...NzczfQ.zUUd...KHTkM"
    }
}

#Använda JSON Web Tokens

Vi ser att svaret från Lager API:t innehåller attributet token och detta är vår JWT som vi använder varje gång vi vill åt funktioner i API:t som ligger bakom skyddet. Vi skickar med token som x-access-token i HTTP-headern.

I mithril kan du skicka med headers på följande sätt.

let token = "...";

m.request({
    method: "GET",
    url: "/v2/invoices?api_key=[YOUR_API_KEY]",
    headers: {
        "x-access-token": token
    }
}).then(function(result) {
    // Do something with result
});

I mithrils dokumentation ges ett exempel på hur man kan hantera om en användare är inloggad eller ej och visa olika beroende på status.

#Exempelprogram

I example/bakery exempelprogrammet finns ett exempel på hur man kan använda sig av JWT för att skydda vissa delar av en app.

Jag har i exempelprogrammet skapat en autentiserings-modell auth. Modellen håller koll på om användaren är inloggad eller ej beroende på om det finns innehåll i attributet auth.token.

import m from 'mithril';

const auth = {
    apiKey: "[API_KEY]",
    url: "https://lager.emilfolino.se/v2/auth/login",
    email: "",
    password: "",
    token: "",
    login: function() {
        return m.request({
            method: "POST",
            url: auth.url,
            body: {
                api_key: auth.apiKey,
                email: auth.email,
                password: auth.password
            }
        }).then(function(result) {
            auth.email = "";
            auth.password = "";

            auth.token = result.data.token;

            return m.route.set("/");
        });
    }
};

export { auth };

Dessutom finns funktionen auth.login som kan användas för att logga in i systemet med. Själva kontrollen av om vi från klienten får gå till routen /new för att skapa nya produkter görs i routern i js/index.js. Först kollar vi om token är satt i auth-modellen annars gör vi en redirect till login-sidan. newForm som returneras från onmatch skickas in till render-funktionen som parametern vnode och vi kan sedan använda den för att rita ut formuläret.

"/new": {
    onmatch: function() {
        if (auth.token) {
            return newForm;
        } else {
            return m.route.set("/login");
        }
    },
    render: function(vnode) {
        return m(layout, {
            topNav: { route: "#!/", title: "Hem"},
            bottomNav: "#!/new"
        }, vnode);
    }
},

För att vi ska kunna logga in behövs ett inloggningsformulär. I filen js/views/login.js finns formuläret och för enkelhetens skulle har jag för registrerat en användare om ni vill testa exempelprogrammet.

import m from 'mithril';

import { auth } from "../models/auth.js";

let login = {
    view: function() {
        return m("div.container",
            m("h2", "Logga in"),
            m("p", "Finns en registrerad användare: kaka@kaka.se, Lösenord: test1234"),
            m("form", {
                onsubmit: function(event) {
                    event.preventDefault();
                    auth.login();
                } }, [
                m("label.input-label", "E-post"),
                m("input.input[type=email][placeholder=E-post]", {
                    oninput: function (e) {
                        auth.email = e.target.value;
                    },
                    value: auth.email
                }),
                m("label.input-label", "Lösenord"),
                m("input.input[type=password][placeholder=Lösenord]", {
                    oninput: function (e) {
                        auth.password = e.target.value;
                    },
                    value: auth.password
                }),
                m("input.button.green-button[type=submit][value=Logga in].button")
            ]));
    }
};

export { login };

#Avslutningsvis

Vi har i denna artikel använd oss av Postman för att registrera en användare och logga in med den användaren. Vi har även tittat på hur man kan använda headers som en del av ett anrop i mithrils m.request funktion. Vi har även tittat på hur man kan implementera en fullständig autentiseringslösning i mithril i exempelprogrammet example/bakery.

#Revision history

  • 2018-02-07: (A, efo) Första utgåvan inför kursen webapp v3.

Document source.

Category: javascript.