Disclaimer: Dit artikel is gegenereerd door automatische vertaling.

Implementeer JWT in je applicatie

Prev Next

Na het voltooien van de JWT-configuratie in Document360 heeft uw applicatie een backendroute nodig om de laatste stap van de inlogflow af te handelen.

Deze route:

  • Valideert dat de gebruiker al geauthenticeerd is in je applicatie
  • Stuurt een beveiligd verzoek naar de codegeneratie-URL van Document360
  • Haalt een eenmalige autorisatiecode op
  • Leidt de gebruiker door naar de kennisbanksite met die code

OPMERKING

Lezers hebben geen apart Document360-account nodig. Authenticatie wordt volledig via uw applicatie afgehandeld. Een account in uw applicatie is voldoende voor een lezer om toegang te krijgen tot de kennisbank.


Codevoorbeelden

De onderstaande voorbeelden laten zien hoe je de backend-authenticatieroute in C#, Node.js en Java kunt implementeren.

C #

/// <summary>
/// Example endpoint to authenticate a user and retrieve a token from the identity server,
/// and redirect the user to the Knowledge Base (KB) using the token code.
/// </summary>
/// <param name="clientId">Client ID issued for your application</param>
/// <param name="clientSecret">Client secret associated with the client ID</param>
/// <returns>Redirects to the KB with the issued code</returns>
[HttpGet]
[Route("authenticate")]
public async Task<IActionResult> AuthenticateAsync(string clientId, string clientSecret)
{
    if (!HttpContext.User.Identity.IsAuthenticated)
    {
        // user is not authenticated, redirect to an error or login page
        return Unauthorized(new { message = "User not authenticated" });
    }

    // Ensure you have the correct client ID and secret from your Document360 JWT configuration
    var authToken = Encoding.ASCII.GetBytes($"{clientId}:{clientSecret}");

    // Create an HttpClient instance
    using var httpClient = new HttpClient();

    // Set the Authorization header with Basic authentication
    httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(authToken));

    // Prepare the payload with user information
    var payload = new
    {
        username = User.Identity.Name,
        firstName = "FirstName", // Replace or customize as needed
        lastName = "LastName",
        emailId = "user@example.com", // Replace with actual user email
        readerGroupIds = new List<string> { "group1", "group2" }, // Replace with actual reader group IDs if needed (Optional)
        tokenValidity = 3600, // Token validity in seconds (Optional, default is 5 minutes)
        providerName = "app.example.com" // Domain of the matching JWT configuration (Required when multiple JWT configurations are active)
    };

    var payloadContent = new StringContent(JsonConvert.SerializeObject(payload), Encoding.UTF8, "application/json");

    // Identity server token endpoint - replace with your actual URL
    string identityServerUrl = "codeGeneration endpoint, you can find that in JWT config portal";
    // KB login URL to redirect after successful token issuance
    string kbLoginUrl = "https://{your subdomain}.document360.io";

    var response = await httpClient.PostAsync(identityServerUrl, payloadContent);

    if (response.IsSuccessStatusCode)
    {
        var content = await response.Content.ReadAsStringAsync();
        var tokenJson = JObject.Parse(content);
        // Extract the code from the response
        var tokenCode = (string)tokenJson.SelectToken("code");

        // Construct the KB login URL with code query parameter
        string finalRedirectUrl = $"{kbLoginUrl}?code={tokenCode}";

        return Redirect(finalRedirectUrl);
    }
    else
    {
        // Handle error response from the identity server
        var error = await response.Content.ReadAsStringAsync();
        return StatusCode((int)response.StatusCode, new { error = "Token request failed", details = error });
    }
}

Node.js

const express = require('express');
const https = require('https');
const axios = require('axios');
const app = express();

app.use(express.json());

const clientId = 'your-client-id';
const clientSecret = 'your-client-secret';
const codeGenerationUrl = 'https://identity.document360.net/jwt/generateCode';
const kbLoginUrl = 'https://your-subdomain.document360.net/jwt/authorize';

app.get('/authenticate', async (req, res) => {
  try {
    const isAuthenticated = true; // Replace with your actual auth logic

    if (!isAuthenticated) {
      return res.status(401).json({ message: 'User not authenticated' });
    }

    const authHeader = Buffer.from(`${clientId}:${clientSecret}`).toString('base64');

    const payload = {
      username: 'john.doe',
      firstName: 'John',
      lastName: 'Doe',
      emailId: 'john.doe@example.com',
      readerGroupIds: ['group1', 'group2'],
      tokenValidity: 3600,
      providerName: 'app.example.com' // Domain of the matching JWT configuration
    };

    const response = await axios.post(
      codeGenerationUrl,
      payload,
      {
        headers: {
          'Authorization': `Basic ${authHeader}`,
          'Content-Type': 'application/json',
          'Accept': 'application/json'
        },
        httpsAgent: new https.Agent({ maxVersion: 'TLSv1.2' })
      }
    );

    const tokenCode = response.data?.code;

    if (!tokenCode) {
      return res.status(500).json({ message: 'No code received from Document360' });
    }

    console.log("Redirecting to:", `${kbLoginUrl}?code=${tokenCode}`);
    return res.redirect(`${kbLoginUrl}?code=${tokenCode}`);

  } catch (error) {
    return res.status(500).json({
      message: 'JWT SSO failed',
      details: error.response?.data || error.message
    });
  }
});

Java

import org.springframework.http.*;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;

import java.nio.charset.StandardCharsets;
import java.util.*;

@RestController
public class JwtSsoController {

    private final String clientId = "your-client-id";
    private final String clientSecret = "your-client-secret";
    private final String codeGenerationUrl = "https://identity.document360.io/api/jwt/generate-code";
    private final String kbLoginUrl = "https://your-subdomain.document360.io/jwt/authorize";

    @GetMapping("/authenticate")
    public ResponseEntity<?> authenticate() {
        // Example: Check if user is authenticated in your system
        boolean isAuthenticated = true; // Replace with actual logic
        if (!isAuthenticated) {
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("User not authenticated");
        }

        // Create Basic Auth header
        String auth = clientId + ":" + clientSecret;
        String encodedAuth = Base64.getEncoder().encodeToString(auth.getBytes(StandardCharsets.UTF_8));
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.set("Authorization", "Basic " + encodedAuth);
        headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));

        // Construct payload
        Map<String, Object> payload = new HashMap<>();
        payload.put("username", "john.doe");
        payload.put("firstName", "John");
        payload.put("lastName", "Doe");
        payload.put("emailId", "john.doe@example.com");
        payload.put("readerGroupIds", Arrays.asList("group1", "group2"));
        payload.put("tokenValidity", 3600);
        payload.put("providerName", "app.example.com"); // Domain of the matching JWT configuration

        HttpEntity<Map<String, Object>> request = new HttpEntity<>(payload, headers);
        RestTemplate restTemplate = new RestTemplate();

        try {
            ResponseEntity<Map> response = restTemplate.postForEntity(codeGenerationUrl, request, Map.class);

            if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
                String tokenCode = (String) response.getBody().get("code");

                if (tokenCode == null || tokenCode.isEmpty()) {
                    return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                            .body("No code returned from Document360");
                }

                // Redirect to the KB site with code
                String redirectUrl = UriComponentsBuilder.fromHttpUrl(kbLoginUrl)
                        .queryParam("code", tokenCode)
                        .toUriString();

                HttpHeaders redirectHeaders = new HttpHeaders();
                redirectHeaders.setLocation(java.net.URI.create(redirectUrl));
                return new ResponseEntity<>(redirectHeaders, HttpStatus.FOUND);

            } else {
                return ResponseEntity.status(HttpStatus.BAD_GATEWAY)
                        .body("Failed to get code from Document360: " + response.getStatusCode());
            }

        } catch (Exception ex) {
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body("JWT SSO error: " + ex.getMessage());
        }
    }
}

Lezers opnieuw authenticeren met meerdere JWT-configuraties

Wanneer de sessie van een lezer verloopt, stuurt Document360 deze om opnieuw in te loggen. De doorleiding hangt af van hoeveel JWT-configuraties er actief zijn in je project:

  • Eén JWT-configuratie: Document360 leidt de lezer direct door naar de geconfigureerde Login URL.
  • Meerdere JWT-configuraties: Document360 kan niet zien via welke configuratie de lezer is ingelogd, dus de lezer belandt op een inlogpagina en moet zijn domein invoeren.

Om lezers direct terug te sturen naar de juiste Login-URL, voeg providerName je toe aan de payload die je backend stuurt naar de Codegeneratie-URL. Stel de waarde ervan in op het domein van de bijbehorende JWT-configuratie, beschikbaar in Instellingen > Gebruikers & Rechten > JWT.

{
  "username": "john.doe",
  "firstName": "John",
  "lastName": "Doe",
  "emailId": "john.doe@example.com",
  "readerGroupIds": ["group1", "group2"],
  "tokenValidity": 3600,
  "providerName": "app.example.com"
}

Hoe het werkt

  1. Je aanvraag wordt providerName verzonden wanneer de lezer inlogt.
  2. Document360 registreert de JWT-configuratie waarmee de lezer is ingelogd.
  3. Wanneer de sessie verloopt, stuurt Document360 de lezer direct door naar de Login-URL van die configuratie, zonder de domeinpagina te tonen.

OPMERKING

Als je project slechts één JWT-configuratie heeft, providerName is dat optioneel. Document360 verwijst lezers al door naar de geconfigureerde Login-URL bij het verstrijken van de sessie.


Ontwikkelaarschecklist

Controleer het volgende voordat je live gaat:

  • Registreer de Login-URL, Callback-URL en Codegeneratie-URL in je JWT-instellingen.
  • Bewaar het klantgeheim veilig. Het wordt slechts één keer weergegeven op het moment van aanmaken.
  • Implementeer backendlogica om de Code generatie-URL aan te roepen met HTTP Basic Auth.
  • Teken de JWT in je backend met je client secret. Stel nooit de signinglogica bloot aan de clientzijde.
  • Als je project meerdere JWT-configuraties heeft, voeg providerName dan de payload toe met het domein van de bijbehorende configuratie.
  • Handhaaf HTTPS op alle endpoints die betrokken zijn bij de authenticatieflow.
  • Test sessiegedrag, tokenverloop en automatische sessievernieuwing voordat je live gaat.
  • Monitor backend-logs op 401-fouten, die doorgaans wijzen op verlopen autorisatiecodes of token-mismatches.

Doorverwijzen naar een specifieke pagina na het inloggen

Standaard worden lezers na het inloggen doorgestuurd naar de startpagina van je kennisbank.

  • Als je startpagina niet is gepubliceerd, worden lezers doorgestuurd naar die /docs pagina.
  • Om lezers naar een andere pagina in je kennisbank te leiden, configureer je de doorleiding met het volgende URL-patroon.

URL-patroon

https://<Knowledge base URL>/jwt/authorize?code=<code>&redirectUrl=<redirect path>

Parameters

  • <Knowledge base URL>: de hoofd-URL van je kennisbanksite.
  • <code>: de code die wordt gegenereerd door het Document360-codegeneratie-eindpunt.
  • <redirect path>: de URL waar je wilt dat lezers landen na het inloggen.

Voorbeeld

https://example.document360.io/jwt/authorize?code=FOTaS_SW6dLGytQXvrG_rRFGhyPvrDDrgxJAZzYvJcY&redirectUrl=/docs/5-basic-things-to-get-started

OPMERKING

Document360 zal de Redirection-URL redirectPath naar het login-endpoint sturen. Wanneer het login-endpoint terugstuurt naar de kennisbank met de authenticatiecode, zou het de Redirectie-URL als parameter redirectUrl moeten teruggeven.

In KB Site 2.0 wordt redirection afgehandeld met cookies in plaats van de redirectUrl parameter. Als je JWT-implementatie gebaseerd is op querystring-redirectie met de redirectUrl parameter, ondersteunt de cookie-gebaseerde aanpak deze parameter niet. Je moet mogelijk je implementatie bijwerken of contact opnemen met de ondersteuning voor verdere verduidelijking.