C# Academy · Lekcja

Tokeny odświeżania i wygaśnięcie

Implementuj bezpieczne odnawianie tokenów.

Lekcja 4 z 413 kroki

Tokeny odświeżania i wygaśnięcie to bezpłatna lekcja C# Academy na CoddyKit. To lekcja 4 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej C# Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs C# Academy zawiera 4 lekcji w sumie.

Problem z wygasaniem

Krótkotrwałe tokeny dostępu są bezpieczne, ale uciążliwe: zmuszanie użytkowników do logowania co 15 minut zapewnia złą wygodę użytkownika.

Rozwiązaniem jest token odświeżający — osobne poświadczenie o dłuższym czasie ważności, służące do uzyskiwania nowych tokenów dostępu bez ponownego wpisywania hasła.

// access token: 15 minutes
// refresh token: 7-30 days

Czym jest token odświeżający

Token odświeżający to zazwyczaj losowy ciąg znaków o niejawnej treści (a nie JWT). Ponieważ jest długotrwały, musi być przechowywany po stronie serwera, aby można było go unieważnić.

Należy go generować za pomocą kryptograficznie bezpiecznego generatora liczb losowych.

public static string GenerateRefreshToken()
{
    var bytes = new byte[64];
    using var rng = RandomNumberGenerator.Create();
    rng.GetBytes(bytes);
    return Convert.ToBase64String(bytes);
}

Przechowywanie tokenów odświeżających

Każdy token odświeżający należy zapisać wraz z jego właścicielem, terminem wygaśnięcia i flagą unieważnienia. Umożliwia to unieważnienie tokenu podczas wylogowania lub po jego kradzieży.

public class RefreshToken
{
    public int Id { get; set; }
    public string Token { get; set; } = default!;
    public int UserId { get; set; }
    public DateTime ExpiresAt { get; set; }
    public bool IsRevoked { get; set; }
}

Wystawianie obu tokenów podczas logowania

Po pomyślnym zalogowaniu należy zwrócić krótkotrwały token dostępu oraz nowy token odświeżający. Token odświeżający należy zapisać w bazie danych.

var access = tokenService.CreateAccessToken(user);
var refresh = new RefreshToken
{
    Token = TokenService.GenerateRefreshToken(),
    UserId = user.Id,
    ExpiresAt = DateTime.UtcNow.AddDays(7)
};
db.RefreshTokens.Add(refresh);
await db.SaveChangesAsync();
return Results.Ok(new { access, refresh = refresh.Token });

Endpoint odświeżania

Dedykowany endpoint /refresh przyjmuje token odświeżający i, jeśli jest on prawidłowy, wystawia zupełnie nowy token dostępu.

app.MapPost("/refresh", async (RefreshDto dto, AppDb db, TokenService tokens) =>
{
    var stored = await db.RefreshTokens
        .SingleOrDefaultAsync(r => r.Token == dto.RefreshToken);

    if (stored is null || stored.IsRevoked ||
        stored.ExpiresAt < DateTime.UtcNow)
        return Results.Unauthorized();

    var user = await db.Users.FindAsync(stored.UserId);
    var access = tokens.CreateAccessToken(user!);
    return Results.Ok(new { access });
});

Rotacja tokenów odświeżających

Rotacja zwiększa bezpieczeństwo tego procesu: za każdym razem, gdy token odświeżający zostanie użyty, należy go unieważnić i wystawić nowy. Skradziony, wcześniej użyty token staje się wtedy bezużyteczny.

stored.IsRevoked = true;            // burn the old one
var next = new RefreshToken
{
    Token = TokenService.GenerateRefreshToken(),
    UserId = stored.UserId,
    ExpiresAt = DateTime.UtcNow.AddDays(7)
};
db.RefreshTokens.Add(next);
await db.SaveChangesAsync();

Wykrywanie ponownego użycia tokenu

Rotacja umożliwia wykrywanie kradzieży: jeśli wcześniej unieważniony token zostanie ponownie przedstawiony, należy potraktować to jako naruszenie bezpieczeństwa i unieważnić całą rodzinę tokenów użytkownika.

if (stored.IsRevoked)
{
    // This token was already used - likely stolen.
    await RevokeAllUserTokens(stored.UserId, db);
    return Results.Unauthorized();
}

Wylogowanie i unieważnianie

Wylogowanie po prostu unieważnia bieżący token odświeżający. Token dostępu sam wygaśnie w ciągu kilku minut.

app.MapPost("/logout", async (RefreshDto dto, AppDb db) =>
{
    var stored = await db.RefreshTokens
        .SingleOrDefaultAsync(r => r.Token == dto.RefreshToken);
    if (stored is not null) stored.IsRevoked = true;
    await db.SaveChangesAsync();
    return Results.Ok();
}).RequireAuthorization();

Gdzie przechowywać tokeny po stronie klienta

W przypadku przeglądarek najbezpieczniejszym rozwiązaniem jest przechowywanie tokenu odświeżającego w ciasteczku HttpOnly, Secure, aby JavaScript nie mógł go odczytać, co ogranicza ryzyko kradzieży za pomocą XSS.

Krótkotrwały token dostępu można przechowywać w pamięci.

Response.Cookies.Append("refresh", refresh.Token, new CookieOptions
{
    HttpOnly = true,
    Secure = true,
    SameSite = SameSiteMode.Strict,
    Expires = refresh.ExpiresAt
});

Usuwanie wygasłych tokenów

Tokeny odświeżające z czasem się gromadzą. Należy uruchamiać okresowe zadanie w tle (np. usługę hostowaną), aby usuwać wygasłe lub unieważnione wiersze.

await db.RefreshTokens
    .Where(r => r.ExpiresAt < DateTime.UtcNow || r.IsRevoked)
    .ExecuteDeleteAsync();

Dobór okresów ważności

Należy znaleźć równowagę między bezpieczeństwem a wygodą:

  • Token dostępu: 5–15 minut — ogranicza zakres wykorzystania tokenu, który wyciekł.
  • Token odświeżający: od kilku godzin do kilku tygodni, zależnie od wrażliwości danych.
  • W przypadku okresu dłuższego niż dzień należy stosować rotację.
AccessTokenLifetime  = TimeSpan.FromMinutes(15);
RefreshTokenLifetime = TimeSpan.FromDays(7);

Szybkie sprawdzenie

Proszę sprawdzić swoją wiedzę na temat procesu odświeżania.

Podsumowanie

Zaimplementowano proces tokenów odświeżających:

  • Wystawia się krótko ważny token dostępu oraz długi, nieprzejrzysty token odświeżający przechowywany po stronie serwera.
  • Endpoint /refresh wymienia prawidłowy token odświeżający na nowy token dostępu.
  • Rotacja i wykrywanie ponownego użycia zwiększają ochronę przed kradzieżą.
  • Tokeny odświeżające należy przechowywać w ciasteczkach HttpOnly i usuwać wygasłe wiersze.

To kończy kurs uwierzytelniania JWT.

Bezpłatny start

Ucz się C# dzięki korepetycjom AI — za darmo

Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.

Kursy
93
Lekcje
346

Często zadawane pytania

Czy lekcja „Tokeny odświeżania i wygaśnięcie” jest bezpłatna?

Tak — pełny tekst „Tokeny odświeżania i wygaśnięcie” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu C# Academy, przejdź na CoddyKit PRO. Kurs C# Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Tokeny odświeżania i wygaśnięcie”?

Implementuj bezpieczne odnawianie tokenów. Ćwiczysz C# Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć C# Academy?

Nie wymagamy żadnego doświadczenia. C# Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 4 z 4.

Ile czasu zajmuje lekcja „Tokeny odświeżania i wygaśnięcie”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji C# Academy?

Tak. Każda lekcja C# Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Struktura JWT i deklaracje
  2. Konfigurowanie uwierzytelniania JWT Bearer
  3. Wystawianie tokenów
  4. Tokeny odświeżania i wygaśnięcie
← Powrót do C# Academy