Cookies en sessies

Finch biedt twee mechanismen om gegevens tussen HTTP-verzoeken te bewaren: cookies (client-side) en sessies (server-side). Het verschil begrijpen helpt je het juiste middel te kiezen:

  • Cookies worden opgeslagen in de browser en meegestuurd met elk verzoek. Ze zijn geschikt voor lichte gebruikersvoorkeuren (thema, taal) die veilig client-side kunnen worden opgeslagen.
  • Sessies worden op de server opgeslagen. Alleen een sessie-ID wordt naar de browser gestuurd. Ze zijn geschikt voor gevoelige gegevens, zoals de momenteel ingelogde gebruiker.

Beide zijn toegankelijk via het rq-object binnen elke controller of routehandler.

Cookies

Cookies zijn key-value-stringparen die in de browser worden opgeslagen. Finch leest ze uit inkomende Cookie-headers en schrijft ze via Set-Cookie-antwoordheaders.

Gebruik rq.getCookie(key, def: defaultValue) om een cookie te lezen. De def-parameter geeft aan wat er wordt geretourneerd als de cookie niet bestaat.

safe staat bij zowel getCookie als addCookie standaard op true. Tenzij je anders aangeeft, wordt elke cookie die Finch leest of schrijft transparant versleuteld/ontsleuteld. Om een echt platte-tekstwaarde op te slaan of te lezen (leesbaar in de devtools van de browser), moet je expliciet safe: false doorgeven:

// Versleuteld (standaard) — wordt automatisch ontsleuteld bij het terug lezen met getCookie
var token = rq.getCookie('auth_token', def: '');

// Onversleuteld — de waarde wordt exact zo opgeslagen en teruggegeven als opgegeven
var theme = rq.getCookie('theme', def: 'light', safe: false);

Gebruik rq.addCookie(key, value) om een cookie in te stellen. De cookie wordt aan het antwoord toegevoegd:

// Versleuteld (standaard)
rq.addCookie('auth_token', 'abc123');

// Onversleuteld
rq.addCookie('theme', 'dark', safe: false);

addCookie accepteert ook fijnmaziger opties voor de onderliggende Set-Cookie-header:

rq.addCookie(
  'session_pref',
  'compact',
  safe: false,
  duration: Duration(days: 30), // stelt Max-Age in
  path: '/',                    // standaard is '/'
  domain: '.example.com',
  secure: true,                 // alleen verzenden over HTTPS
  httpOnly: true,                // niet leesbaar vanuit JavaScript
  sameSite: SameSite.lax,
);

Om een cookie te verwijderen, zet Finch deze opnieuw met een verlopen max-age:

rq.removeCookie('theme');

Volledig voorbeeld

class CookieController extends Controller {
  Future<String> showCookie() async {
    var value = rq.getCookie('test', def: 'not set', safe: false);
    rq.addParam('cookieValue', value);
    return rq.renderView(path: 'example/cookie');
  }

  Future<String> addCookie() async {
    var key   = rq.get<String>('key', def: '');
    var value = rq.get<String>('value', def: '');
    var safe  = rq.get<bool>('safe', def: false);

    if (key.isNotEmpty) {
      rq.addCookie(key, value, safe: safe);
    }
    return rq.redirect('/example/cookie');
  }
}

Sessies

Sessies worden beheerd door Dart's ingebouwde HttpSession. Elke bezoeker krijgt een unieke sessie-ID die wordt opgeslagen in een browsercookie, maar de daadwerkelijke gegevens bevinden zich op de server in het geheugen.

Belangrijk: De standaard Dart-HttpSession wordt in het geheugen bijgehouden. Sessiegegevens gaan verloren wanneer de server opnieuw opstart en worden niet gedeeld tussen meerdere serverinstanties achter een load balancer. Overweeg voor productiegebruik op schaal een persistente/gedeelde sessieopslag, of sla kritieke gegevens in plaats daarvan op in de database.

Een sessiewaarde lezen

Gebruik rq.getSession(key, def: defaultValue) om een waarde te lezen. Het retourneert def als de sleutel niet bestaat. Let op: het retourtype is Object, niet String — cast het als je een specifiek type nodig hebt:

var userEmail = rq.getSession('user', def: '') as String;

Een sessiewaarde schrijven

Gebruik rq.addSession(key, value) om een waarde op te slaan in de huidige sessie. De waarde kan elk JSON-vriendelijk type zijn (String, num, bool, Map, List), niet alleen strings:

rq.addSession('user', '[email protected]');
rq.addSession('cart', {'items': 3, 'total': 42.5});

Een sessiewaarde verwijderen

rq.session.remove('user');

Volledig voorbeeld

Een typische login/logout/dashboard-flow met sessies:

class SessionController extends Controller {
  Future<String> login() async {
    var email    = rq.get<String>('email', def: '');
    var password = rq.get<String>('password', def: '');

    if (isValidUser(email, password)) {
      // Sla het e-mailadres van de gebruiker op in de sessie na succesvolle authenticatie
      rq.addSession('user', email);
      return rq.redirect('/dashboard');
    }
    return rq.renderError(401);
  }

  Future<String> logout() async {
    // Verwijder de gebruiker uit de sessie om uit te loggen
    rq.session.remove('user');
    return rq.redirect('/login');
  }

  Future<String> dashboard() async {
    var email = rq.getSession('user', def: '') as String;

    // Als er geen sessie is, is de gebruiker niet ingelogd — doorverwijzen naar login
    if (email.isEmpty) return rq.redirect('/login');

    rq.addParam('email', email);
    return rq.renderView(path: 'pages/dashboard');
  }
}

Voor een volledige authenticatieflow met permissies en routebeveiliging, zie Auth Controller — deze bouwt voort op dezelfde getSession/addSession-aanroepen die hier zijn getoond.

De versleutelingssleutel is FinchConfigs.cookiePassword:

FinchConfigs configs = FinchConfigs(
  cookiePassword: env.get('COOKIE_SECRET', 'change-this-in-production'),
);
// Schrijven — wordt versleuteld opgeslagen in de browser
rq.addCookie('prefs', '{"theme":"dark"}');

// Terug lezen — Finch ontsleutelt dit automatisch
var prefs = rq.getCookie('prefs', def: '{}');

Omdat de versleuteling is gekoppeld aan cookiePassword, maakt het wijzigen van die waarde elke cookie die al is opgeslagen in de browsers van bezoekers ongeldig — getCookie kan ze dan niet meer ontsleutelen en valt stilzwijgend terug op def.

Beveiliging: Gebruik een lange, willekeurige cookiePassword. Sla deze op als omgevingsvariabele. Hardcode deze nooit en commit hem nooit naar versiebeheer.

Cookies lezen in sjablonen

Je kunt een cookiewaarde ook rechtstreeks binnen een Jinja-sjabloon lezen:

{{ $e.getCookie('theme', 'light') }}

Zie Template voor al het andere dat beschikbaar is op $e binnen een sjabloon.