Remote login gør det muligt for et medlem at logge ind i Bookhus via jeres medlemsportal og fortsætte til booking af et bestemt emne.
Jeres medlemsportal skal kontrollere medlemmets identitet og adgang, inden den sender brugeren til Bookhus.
Flow
- Medlemmet vælger et emne i Bookhus eller i jeres medlemsportal.
- Medlemmet logger ind på jeres medlemsportal.
- Jeres server opretter en tidsbegrænset token og en JSON-pakke med medlemsnøglen og den ønskede returadresse.
- JSON-pakken krypteres, og browseren omdirigeres til Bookhus’ remote login-endpoint.
- Bookhus validerer tokenen, finder brugeren og logger vedkommende ind. Hvis brugeroprettelse er aktiveret, kan Bookhus også oprette en bruger, som ikke findes.
- Efter gennemført login sendes medlemmet til returadressen, eksempelvis
/book/1234.
Opsætning i Bookhus
Hvis gæster skal sendes fra Bookhus til jeres medlemsportal, angives portalens loginadresse under bookingregler på:
https://{DOMÆNE}/admin/settings
Eksempel:
https://medlemsportal.example/login?houseId={houseid}Bookhus erstatter {houseid} med det valgte emnes numeriske id. Jeres medlemsportal skal bevare dette id gennem loginflowet og bruge det til at danne returadressen.
Aktivér indstillingerne:
- Gå til denne side i stedet for book
- Dette gælder kun for gæst
Hvis Bookhus skal kunne oprette medlemmer, der endnu ikke findes, aktiveres desuden Remote login opretter brugere som ikke findes under brugerindstillinger. Denne indstilling er valgfri; uden den skal brugeren allerede findes i Bookhus.

API-nøgler
Nøglerne administreres på:
https://{DOMÆNE}/Admin/Security/ApikeysIntegrationen anvender to nøgler med forskellige formål:
| Beskrivelse | Formål |
|---|---|
RemoteLogin | Den hemmelige nøgle, som bruges til at generere login-tokenen. |
RemoteLoginCrypto | Nøglen, som bruges til at kryptere JSON-pakken. |
Begge nøgler skal være korrekt opsat og gyldige. Opbevar dem på jeres server. Token og krypteret loginpakke skal genereres på serveren.
Endpoint og JSON-pakke
Endpointet tilgås med et GET-kald:
https://{DOMÆNE}/account/remotelogin2?data={URL-ENCODET_KRYPTERET_PAKKE}JSON-pakken indeholder følgende felter:
| Felt | Betydning |
|---|---|
token | En tidsbegrænset token på seks cifre, sendt som tekst. |
data | Brugerens medlemsnummer hos Bookhus, sendt som tekst. |
redirectUrl | Den lokale sti, som brugeren skal sendes til efter login. |
firstName | Valgfrit fornavn, som kan bruges ved brugeroprettelse. |
lastName | Valgfrit efternavn, som kan bruges ved brugeroprettelse. |
Eksempel før kryptering:
{ "token": "123456", "data": "<MEDLEMSNUMMER>", "redirectUrl": "/book/1234", "firstName": "Anna", "lastName": "Jensen" }Brug feltnavnene med præcis den viste stavemåde.
Medlemsnummer
Bookhus bruger værdien i data til at slå brugeren op via medlemsnummer.
Hvis jeres integration anvender CPR-nummer som medlemsnøgle, skal CPR-nummeret derfor være registreret som medlemsnummer i Bookhus. Det er ikke tilstrækkeligt, at det alene findes i brugerens CPR-felt.
Send værdien som tekst, så eventuelle foranstillede nuller bevares.
Returadresse efter login
Returadressen skal sendes som feltet redirectUrl inde i den krypterede JSON-pakke:
"redirectUrl": "/book/1234"1234 er emnets numeriske id i Bookhus (House.Id).
En ekstra queryparameter som &ReturnUrl=/book/1234 bliver ikke læst af remotelogin2.
Brug en lokal sti, der begynder med /, uden protokol og domæne. Hvis returadressen mangler eller ikke accepteres som lokal, sendes brugeren som udgangspunkt til /.
Kryptering og token
JSON-pakken krypteres med den eksisterende Bookhus-protokol:
- AES med CBC og PKCS7-padding.
- Krypteringsnøglen anvendes som UTF-8-bytes.
- IV består af 16 nulbytes og medsendes ikke.
- Det krypterede resultat konverteres til Base64.
- Base64-værdien URL-encodes, inden den indsættes i URL’en.
Tokenen genereres med HMAC-SHA1, seks cifre og tidsintervaller på 30 sekunder. Tokennøglen anvendes som rå ASCII-bytes; den skal ikke Base32- eller Base64-dekodes.
Bookhus accepterer det aktuelle tidsinterval samt ét interval før og efter. Servernes ure skal derfor være synkroniserede. Generér loginlinket umiddelbart inden omdirigering.
C#-eksempel: Kryptering
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
public static class AESCrypto
{
public static string EncryptString(string key, string text)
{
using (var aes = Aes.Create())
{
aes.Key = Encoding.UTF8.GetBytes(key);
aes.IV = new byte[16];
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
using (var encryptor = aes.CreateEncryptor())
using (var ms = new MemoryStream())
{
using (var cs = new CryptoStream(
ms, encryptor, CryptoStreamMode.Write))
using (var sw = new StreamWriter(
cs, new UTF8Encoding(false)))
{
sw.Write(text);
}
return Convert.ToBase64String(ms.ToArray());
}
}
}
}
C#-eksempel: Token
using System;
using System.Globalization;
using System.Security.Cryptography;
using System.Text;
public static class Twofactor
{
private static readonly DateTime UnixEpoch =
new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
public static string GetPincode(string secret)
{
var counter =
(long)(DateTime.UtcNow - UnixEpoch).TotalSeconds / 30;
var counterBytes = BitConverter.GetBytes(counter);
if (BitConverter.IsLittleEndian)
{
Array.Reverse(counterBytes);
}
using (var hmac = new HMACSHA1(Encoding.ASCII.GetBytes(secret)))
{
var hash = hmac.ComputeHash(counterBytes);
var offset = hash[hash.Length - 1] & 0x0f;
var binary =
((hash[offset] & 0x7f) << 24)
| ((hash[offset + 1] & 0xff) << 16)
| ((hash[offset + 2] & 0xff) << 8)
| (hash[offset + 3] & 0xff);
return (binary % 1000000)
.ToString("D6", CultureInfo.InvariantCulture);
}
}
}
C#-eksempel: Omdirigering til booking
Eksemplet forudsætter, at medlemsportalen allerede har autentificeret medlemmet og kontrolleret adgang. Medlemsnummeret skal hentes fra den autentificerede medlemsprofil.
public ActionResult GoToBooking(int houseId)
{
// Hentes fra serverens beskyttede konfiguration.
var cryptoKey = "<RemoteLoginCrypto SecretKey>";
var tokenKey = "<RemoteLogin SecretKey>";
var domain = "cs.bookhus.dk";
// Hentes fra det autentificerede medlem.
var medlemsnummer = "<MEDLEMSNUMMER>";
var package = new
{
token = Twofactor.GetPincode(tokenKey),
data = medlemsnummer,
redirectUrl = "/book/" +
houseId.ToString(
System.Globalization.CultureInfo.InvariantCulture)
};
var json = Newtonsoft.Json.JsonConvert.SerializeObject(package);
var encryptedData = AESCrypto.EncryptString(cryptoKey, json);
var link = string.Format(
"https://{0}/account/remotelogin2?data={1}",
domain,
System.Uri.EscapeDataString(encryptedData));
return Redirect(link);
}Begrænsninger i den nuværende implementering
Remote login er ikke en generel synkronisering af medlemsprofiler. Eksisterende brugeres navn opdateres ikke automatisk ved hvert login.
Hvis brugeren skal gennemføre yderligere totrinsbekræftelse i Bookhus, videreføres redirectUrl ikke korrekt i den nuværende implementering. Dette kræver en rettelse i Bookhus, hvis integrationen skal understøtte dette flow.
Teksten er kontrolleret mod den lokale kildekode; drift og kodeeksempler er ikke afprøvet. Ingen filer ændret eller builds/tests kørt. TFVC-status er uændret: seks tilføjede SQL-migrationer og én ændret Web.config.
Var denne artikel nyttig?
Fantastisk!
Tak for din feedback
Beklager, at vi ikke var nyttige
Tak for din feedback
Feedback sendt
Vi sætter pris på din indsats og vil forsøge at rette artiklen