Blogginlägg

Den ultimata utvecklarguiden till BankID

Av Chris Klug | Blogg | 27 oktober 2020

Att sätta up en autentiseringslösning med hjälp av BankID kan vara något av en skrämmande uppgift om man ska vara ärlig. Det är hyffsat väl dokumenterat, men det är många steg som måste göras, både i form av kod och i form av mer administrativa uppgifter. Och när man börjar läsa dokumentationen kring vad som krävs, så inser man snabbt att det kommer ta ett tag att få till. Det är där Active Login kommer in. Active Login är en smidig lösning för att snabbt komma igång med BankID autentisering. Inte nog med att API:et för Active Login bygger på samma API som alla andra autentiserings providers i .NET Core, det hanterar i princip alla de tekniska delarna åt oss.

Men även om både BankID och Active Login är väl dokumenterade, så kan det vara lite struligt att komma igång. Av den anledningen så tänkte vi skriva en steg för steg beskrivning av vad som behövs göras för att få det att fungera.

Komma igång

Active Login kan användas på ett flertal vis. Men de 2 vanligaste är att antingen implementera Active Login i en fristående applikation, eller att integrera det med IdentityServer. Den här artikeln kommer visa båda delarna.

Innan vi sätter igång, så kan det dock vara värt att säga att bara för att det finns en beskrivning av hur man gör här, och att Active Login löser det flesta delarna av BankID integrationen, så innebär det inte att man inte bör läsa igenom BankID’s egna dokumentation också. För även om Active Login är byggt för att följa deras standarder och rekommendationer, så är det trots allt du som implementerar och använder det som är ytterst ansvarig.

Och med den disclaimern ur värden, så är det äntligen dags att ta en titt på hur man implementerar BankID autentisering med Active Login.

NuGet-paket

Det första steget är att sätta upp en ASP.NET Core applikation. För den här demon så har jag skapat en ny tom ASP.NET Core applikation I Visual Studio 2019.

När vi väl har en applikation som behöver BankID autentisering, så är det dags att installera ett antal NuGet paket. Och med ett antal menar jag 3. De är

  • ActiveLogin.Authentication.BankId.AspNetCore
  • ActiveLogin.Authentication.BankId.AspNetCore.QRCoder
  • ActiveLogin.Authentication.BankId.AspNetCore.UAParser

Ska vi vara helt ärliga så behövs strikt sett bara ActiveLogin.Authentication.BankId.AspNetCore paketet, men det är lika bra att ta alla 3 för att få full funktionalitet.

AddAuthentication

Med dessa på plats är det dags att sätta upp ASP.NET Core autentisering med hjälp av Active Login. Det görs med följande kod i ConfigureServices metoden i Startup.cs

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
        .AddBankId(builder => {
            builder
                .AddDebugEventListener()
                .UseQrCoderQrCodeGenerator()
                .UseUaParserDeviceDetection()                     
                .UseSimulatedEnvironment()   
                .AddSameDevice()
                .AddOtherDevice();
        })
        .AddCookie();

De här raderna kod lägger till autentiseringsstöd i applikationen, och lägger till både BankID, med hjälp av AddBankId(), och cookie autentisering, med hjälp av AddCookies().

Det finns ett par saker som kan vara värt att ta en titt på i den här koden. För det första så kan vi se att vi skickar in CookieAuthenticationDefaults.AuthenticationScheme till AddAuthentication(). Detta konfigurerar lösningen till att använda cookie autentisering som standard. Detta behövs då BankID bara är en autentisering, dvs det verifierar att användaren är den hen säger att hen är. För att faktiskt behålla användaren inloggad så måste systemet använda cookie autentisering.

Den andra delen som är intressant att ta en titt på är så klart AddBankId(). Den här metoden är ansvarig för att lägga till Active Logins BankID implementation som ett autentiserings schema.

Konfiguration

På grund av den stora mängd konfiguration som kan göras för detta, så använder Active Login ett “builder pattern” för att sätta upp konfigurationen. Det innebär att man får in ett “builder objekt” på vilket man anropar metoder för att sätta upp konfigurationen. Precis som man gör i till exempel ConfigureServices() metoden själv.

Med hjälp av “buildern” lägger vi sedan till en Debug lyssnare som ger oss användbara loggar under utvecklingen av systemet. Sedan lägger vi till en QrCoder-baserad Qr kods generator som används för att rendera Qr koder vid inloggning. Efter den lägger vi till en “user agent” parser som kan räkna ut vilken type av enhet och webläsare som används för att se till att man kan starta BankID appen på rätt sätt.

Miljö

Sen är det dags att välja miljö att jobba i. Active Login stödjer 3 miljöer, SimulatedTest och Production. Simulated innebär att man inte gör någon riktigt integration. Detta gör det möjligt att lösningen visa hur flödet ser ut och fungerar med hjälp av en simluerad miljö. I princip innebär det bara att BankID inloggningen stegar igenom alla stegen utan att man behöver göra något, och till sist returneras en hårdkodad användare.

För det första steget i den här demon så har vi valt att köraden simluerade miljön och anropar därför UseSimulatedEnvironment().

Scheman

Till sist är det dags att lägga till de faktiska autentiserings scheman som skall användas. Detta görs med AddSameDevice(), som erbjuder användaren att logga in på samma enhet som hen befinner sig, och AddOtherDevice(), som erbjuder användaren att logga in på en annan enhet än den nuvarande.

Eftersom vår lösning vill, precis som de flesta lösningar, erbjuda både inloggning på samma enhet, och på en annan enhet, så anropas vi båda två.

Dessa metoder har ett flertal överlagringar som erbjuder oss att finjustera hur de fungerar. Men för den här demon klarar vi oss med standard värdena.

MVC

När vi fått autentiseringen konfiugurerad är det bara en fråga om att sätta upp ASP.NET MVC. Det gör vi med följande kod i ConfigureServices:

services.AddControllersWithViews(config =>
{
    config.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
});

och

app.UseAuthentication();

app.UseEndpoints(endpoints =>
{
    endpoints.MapDefaultControllerRoute();
});

i Configure metoden.

Med den grundläggande konfigurationen på plats i Startup.cs så kan vi sätta upp en HomeController.cs. I Index actionen så returnerar vi helt enkelt bara en vy

public class HomeController : Controller
{
    public IActionResult Index()
    {
        return View();
    }
}

Vyn i sig är enkel. Det enda som egentligen är viktigt, förutom det vi vill visa på sidan, är att vi inkluderar Bootstrap 4 i vår layout. Så vår layout vy (_Layout.cshtml) ser ut som följer

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>@ViewBag.Title</title>
    <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css" rel="stylesheet" >
</head>
<body>
    <div>
        @RenderBody()
    </div>
</body>
</html>

och vår Index.cshtml ser ut så här:

@if (User.Identity.IsAuthenticated)
{
    <h1>Välkommen @User.Identity.Name</h1>
    <a href="/Account/Logout" class="btn btn-primary">Logga ut</a>
}
else
{
    <a href="/Account/Login?scheme=bankid-samedevice" class="btn btn-primary">Logga in med Bank ID på den här enheten</a><br />
    <a href="/Account/Login?scheme=bankid-otherdevice" class="btn btn-primary">Logga in med Bank ID på en annan enhet</a>
}

Inloggning

Det är nästan allt som behövs. Det enda som saknas nu, är en AccountController.cs som kan hantera Logga in“_ och Logga ut länkarna.

Så för att hantera detta så skapar vi en AccountController med 2 actions. Login och Logout.

public class AccountController : Controller
{
    public IActionResult Login(string scheme)
    {
        return Challenge(new AuthenticationProperties { RedirectUri = "/" }, scheme);
    }

    public async Task<IActionResult> Logout()
    {
        await HttpContext.SignOutAsync();
        return Redirect("/");
    }
}

Som synes här så görs det inte så mycket. Det enda som egentligen görs är att vi anropar de inbyggda autentiseringsmetoderna Challenge() för att skapa en autentiserings "challenge”, och och HttpContext.SignOutAsync() för att logga ut.

Med det på plats är det bara att starta applikationen och prova att logga in och logga ut.

Testsmiljö - Certifikat

När vi har tröttnat på att se applikationen logga in och ut med hjälp av den simulerade miljön, så är det dags att sätta upp en testmiljö. Detta kräver att vi införskaffar ett test certifikat för att kunna kommunicera med BankID, samt ett test BankID som låter oss autentisera oss mot BankIDs testmiljö.

Det första steget är att skaffa ett test certifikat. Detta kan man hämta på BankIDs webbplats. Det är bara att klicka på länken med texten “TLS certificate for test (FPTestcert3_20200618.p12)”. Så fort nedladdningen är klar, flyttar vi certifikatet till rooten på vårt projekt. Därefter måste vi ändra egenskaperna för p12-filen i Visual Studio så att “Copy to Output Directory” är satt till “Copy if newer”.

Problemet är att vi inte litar på utfärdaren av detta certifikat då det är utfärdat av BankID och inte av en av våra betrodda CAs. Så för att kunna använda det så måste vi lita på utfärdaren, på ett eller annat vis. Ett sätt är att lägga till utfärdarens publika nyckel i “Trusted Issuers” i vår “cert store”. Ett annat är att låta Active Login sköta autentiseringen. Vi föredrar det senare eftersom det är lite riskabelt att helt enkelt bara lita på en utfärdare. Även om det faktum att det är BankID gör att det känns relativt säkert.

Men frågan är hur vi får tag I den publika nyckeln för deras CA för testmiljön. Och svaret på det är lite udda. Nyckeln finns I PDF:en BankID Relying Party Guidelines på BankIDs utvecklar info sida. I denna PDF, under punkt 8 “Test Environment” så finns den publika nyckeln. Allt man behöver göra är att kopiera texten mellan raderna “—–BEGIN CERTIFICATE—–” och “—–END CERTIFICATE—–”. Inklusive dessa rader. Och sedan klistra in det i en textfil med filändelsen “.crt”. För den här demon klistrar vi in det I en fil som heter “TestBankIdRootCA.crt” i roten på vårt projekt.

Kommentar: Om du vill verifiera att du fått ner nyckeln korrekt så är det bara att dubbelklicka på filen i utforkaren. Detta ska leda till att ett certifikatsfönster öppnas, och att certifikatets information visas.

Använda testmiljön

Nu när vi har både CA certet och certet för testmiljön, så är det bara att konfigurera om Active Login till att använda test miljön istället för den simulerade. Det gör vi relativt enkelt genom att ersätta UseSimulatedEnvironment() med UseTestEnvironment().

Men före vi kan göra det så måste vi få tag i lite information om miljön vi exekverar i, vilket vi gör med hjälp av IWebHostEnvironment. Så låt oss skapa en konstruktor som får den servicen injicerad, och sparar undan den som en egenskap.

public Startup(IWebHostEnvironment hostingEnvironment)
{
    HostingEnvironment = hostingEnvironment;
}
…
public IWebHostEnvironment HostingEnvironment { get; }

Med IWebHostEnvironment tillgänlig så kan vi ta och byta ut UseSimulatedEnvironment() med:

.UseClientCertificate(() => new System.Security.Cryptography.X509Certificates.X509Certificate2(Path.Combine(HostingEnvironment.ContentRootPath, "FPTestcert3_20200618.p12"), "qwerty123"))
.UseRootCaCertificate(Path.Combine(HostingEnvironment.ContentRootPath, "TestBankIdRootCA.crt"))

Som du ser så registrerar vi både test certifikatet vi laddade ned från BankID och den publika nyckeln från CA certet. Eftersom test certet har en privat nyckel inkluderad så är certifikatet säkrat med ett lösenord som är “qwerty123”.

BankID i testmiljön

Nu är lösningen klar för att kunna testas mot BankIDs testmiljö. Men tyvärr är vår utvecklingsmiljö inte konfigurerad för det. Testmiljön godkänner bara BankIDn som är utfärdade av testmiljön. Så vi kan inte använda vårt vanliga BankID för våra tester. Istället behöver vi konfigurera an BankID app till att använda test certifikat. Och tyvärr funkar BankID appen antingen för produktionsmiljön eller för testmiljön. Den akn inte köra mot båda. Så om du använder BankID till vardags, så är det lättast att se till att du gör testningen på en separat enhet. Det innebär att man antingen behöver en separat mobil/platta för testning av Mobilt BankID, eller en dator som inte använder BankID appen till vardags. Eller båda delarna.

Eftersom jag normalt använder Mobilt BankID till allt, så har jag valt att installera och konfigurera BankID appen på min utvecklingsdator. Det gör man på följande vis.

Först måste man ladda ner och installera BankID appen, vilket man kan göra från https://install.bankid.com/. Efter den installerats behöver man starta appen en gång för att få den färdiguppsatt, innan man stänger av den igen. När appen har stängts av behöver man öppna Utforskaren och gå till %APPDATA%\BankID\Config. I den mappen behöver man sedan skapa en fil som heter CavaServerSelector.txt och som innehåller testen “kundtest” (utan dubbel-fnuttar). Därefter kan man starta upp BankID appen igen.

Kommentar: Om du behöver använda BankID appen för både produktion- och testmiljön, så finns det information om hur du backar upp och återställer dina cert i https://www.bankid.com/assets/bankid/rp/how-to-get-bankid-for-test-v1.7.pdf

Nu när vi har en BankID app som är konfigurerad för att använda BankIDs testmiljö, så är det dags att lägga till ett test BankID. Det gör man genom att surfa till https://demo.bankid.com/. Väl där så klickar man på “Log in” i “Log in with a Production-BankID” sektionen. Därefter loggar man in med Mobilt BankID för att identifiera sig. Detta leder en till en sida där man kan välja att utfärda ett test BankID. Kom bara ihåg att välja “BankID på fil” om du ska använda det på den lokala datorn, inte på en mobil.

När test BankIDt har utfärdats och finns I BankID appen är det bara att starta applikationen I Visual Studio och prova att logga in med knappen “Logga in med BankID på den här enheten”. Detta bör leda till att BankID appen poppar upp och ber om ditt lösenord, följt av att du får se hälsningen som bekräftar att du är inloggad.

Använda BankIDs produktionsmiljö

Att sätta upp Active Login för användning med produktionsmiljön är i sig inte specielt annorlunda än att sätta upp det för test. Den stora skillnaden är att klient certifikatet måste beställas av en leverantör, vilket kan ta ett par dagar, och att den publika nyckeln för CA certet är annorlunda och hämtas i sektion 7 “Production Environment” i PDF:en som användes tidigare.

Därefter är det i huvudsak en fråga om att byta ut UseTestEnvironment() mot UseProductionEnvironment().

Det är dock viktigt att inse att test certifikatet är känslig information, dvs det är inte godkänt att bara lägga den på disk på servern. Istället bör den hanteras som en alla andra känsliga uppgifter och antingen placeras i certifikats hanteringen på servern, eller i en tjänst som Azure KeyVault.

Väljer man att ha sin applikation i Azure så är KeyVault det naturliga valet. Dessutom finns det ett NuGet paket som heter ActiveLogin.Authentication.BankId.AspNetCore.Azure som gör det extremt lätt och smidigt att hämta sitt certifikat från KeyVault.

IdentityServer

Till sist känns det vettigt att skriva ett par rader om integration med IdentityServer4 med tanke på det är väldigt många som använder denna mjukvara.

Som tur är så bygger IdentityServer till stor del på den inbyggda autentideringen i .NET Core. Detta gör att det är extremt lätt att lägga till externa autentiserings scheman så som Facebook och Twitter. Men även BankID med hjälp av Active Login.

Till stor del är det identiskt med det som redan visats. Ända skillnaden är anropen till AddSameDevice() och AddOtherDevice(). Eftersom IdentityServer bygger på att man först loggas in med en temporär inloggning, och sedan “förflyttas” till en permanent, så innebär det att vi inte kan låta Active Login logga in användaren med hjälp av cookie autentisering. Istället måste vi se till att användaren blir inloggad med ett schema som heter IdentityServerConstants.ExternalCookieAuthenticationScheme. Det är dock relativt enkelt att ordna. Allt som behövs är att vi lägger till en konfigurationscallback som sätter SigninScheme

.AddSameDevice(options => { options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme; })
.AddOtherDevice(options => { options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme; })

I övrigt är allt mer eller mindre identiskt med det vi redan gått igenom.

Förhoppningsvis har den här artikeln gjort det lite lättare att förstå hur man sätter upp BankID autentisering med Active Login i ASP.NET Core. Det är inte nödvändigtvis speciellt svårt att sätta sig in i om man jobbat med ASP.NET Core autentisering tidigare. Men det är ett par steg som kanske inte är helt lätta att få grepp om när man läser dokumentationen från Active Login och BankID själva.

Support

Tycker du att BankID är intressant för din app eller webb men tycker allt det tekniska ovan inte är för dig? Våra konsulter hjälper dig gärna med att komma igång och förvalta din inloggningslösning. Läs mer om vårt paket “Säker Bankinloggning” här.

Till inlägget