JWT Authentication ពន្យល់ងាយៗ ពី Header ដល់ Signature ASP.NET Core

JWT Authentication ពន្យល់ងាយៗ ពី Header ដល់ Signature ASP.NET Core

CL
cloudonline
Student·October 5, 2026·0 ចូលចិត្ត

JWT Authentication ពន្យល់ងាយៗ៖ ពី Header ដល់ Signature

នៅពេលអ្នកសរសេរ API ឲ្យ Frontend (React, Vue, Mobile App) ហៅប្រើ សំណួរដំបូងដែលតែងតែកើតឡើងគឺ៖ «តើ Server ដឹងយ៉ាងម៉េចថាអ្នកណាកំពុងហៅ API នេះ?»

ចម្លើយដ៏ពេញនិយមបំផុតសព្វថ្ងៃគឺ JWT (JSON Web Token)។ ក្នុងអត្ថបទនេះ យើងនឹងរៀន៖

  • ភាពខុសគ្នារវាង Authentication និង Authorization
  • រចនាសម្ព័ន្ធ JWT ទាំង ៣ ផ្នែក៖ Header, Payload, Signature
  • Flow ពេញលេញពី Login រហូតដល់ហៅ Protected API
  • របៀបអនុវត្តជាក់ស្តែងក្នុង ASP.NET Core
  • Security Best Practices ដែលអ្នកមិនគួររំលង

1. Authentication ទល់នឹង Authorization

ពាក្យទាំងពីរនេះស្តាប់ទៅស្រដៀងគ្នា ប៉ុន្តែមានន័យខុសគ្នាទាំងស្រុង៖

Authentication Authorization
សំណួរ «តើអ្នកជានរណា?» «តើអ្នកមានសិទ្ធិធ្វើអ្វីខ្លះ?»
ឧទាហរណ៍ Login ដោយ Email + Password មានតែ Admin ទេដែលអាចលុប User
HTTP Status ពេលបរាជ័យ 401 Unauthorized 403 Forbidden
“

[!TIP]
ចាំងាយៗ៖ Authentication ដូចការបង្ហាញអត្តសញ្ញាណប័ណ្ណនៅមាត់ទ្វារអគារ។ Authorization ដូចកាតចូលដែលកំណត់ថាអ្នកអាចចូលជាន់ណាខ្លះ។


2. JWT ជាអ្វី?

JWT គឺជា String មួយដែល Server បង្កើតឡើងបន្ទាប់ពី User Login ជោគជ័យ។ Client រក្សាទុក Token នេះ ហើយផ្ញើវាមកជាមួយរាល់ Request បន្ទាប់ៗ ដើម្បីបញ្ជាក់ថា «ខ្ញុំបាន Login រួចហើយ»។

ចំណុចពិសេសរបស់ JWT គឺវាជា Stateless — មានន័យថា Server មិនចាំបាច់រក្សាទុក Session ក្នុង Memory ឬ Database ទេ។ ព័ត៌មានដែលត្រូវការទាំងអស់ស្ថិតនៅក្នុង Token ខ្លួនឯង ហើយ Server គ្រាន់តែផ្ទៀងផ្ទាត់ Signature ប៉ុណ្ណោះ។

JWT មួយមើលទៅដូចនេះ (បំបែកជា ៣ ផ្នែកដោយសញ្ញា .)៖

text
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjMiLCJuYW1lIjoiRGFyYSIsInJvbGUiOiJBZG1pbiJ9.Xk3p9Qz...
└─────────── Header ──────────────┘ └──────────────────── Payload ────────────────────────────┘ └─ Signature ─┘

3. រចនាសម្ព័ន្ធ JWT ទាំង ៣ ផ្នែក

🔹 Header

ប្រាប់ថា Token នេះប្រើ Algorithm អ្វីសម្រាប់ចុះហត្ថលេខា៖

json
{
  "alg": "HS256",
  "typ": "JWT"
}

🔹 Payload

ផ្ទុកទិន្នន័យអំពី User ដែលហៅថា Claims៖

json
{
  "sub": "123",
  "name": "Dara",
  "role": "Admin",
  "iat": 1759641600,
  "exp": 1759642500
}

Claims ដែលគេប្រើញឹកញាប់៖

  • sub (Subject) — ID របស់ User
  • iat (Issued At) — ពេលវេលាបង្កើត Token
  • exp (Expiration) — ពេលវេលាដែល Token ផុតកំណត់
  • iss / aud — អ្នកចេញ Token និងអ្នកដែល Token នេះសម្រាប់
“

[!WARNING]
Payload ត្រឹមតែត្រូវបាន Base64Url Encode ប៉ុណ្ណោះ — មិនមែន Encrypt ទេ! អ្នកណាក៏អាចយក Token ទៅ Decode មើលបានដែរ (សាកល្បងនៅ jwt.io)។ កុំដាក់ Password, លេខកាតធនាគារ ឬទិន្នន័យសម្ងាត់ក្នុង Payload ជាដាច់ខាត។

🔹 Signature

នេះជាផ្នែកដែលធ្វើឲ្យ JWT មានសុវត្ថិភាព។ Server យក Header និង Payload មកបញ្ចូលគ្នា រួចចុះហត្ថលេខាដោយប្រើ Secret Key ដែលមានតែ Server ទេដែលដឹង៖

text
HMACSHA256(
  base64UrlEncode(header) + "." + base64UrlEncode(payload),
  secretKey
)

ប្រសិនបើ Hacker ព្យាយាមកែ Payload (ឧ. ប្តូរ "role": "User" ទៅជា "Admin") នោះ Signature នឹងលែងត្រូវគ្នា ហើយ Server នឹងបដិសេធ Token នោះភ្លាមៗ។


4. JWT Authentication Flow

text
 ┌──────────┐                                   ┌──────────┐
 │  Client  │                                   │  Server  │
 └────┬─────┘                                   └────┬─────┘
      │  ① POST /api/auth/login                      │
      │     { email, password }                      │
      │ ───────────────────────────────────────────▶ │
      │                                              │ ② ផ្ទៀងផ្ទាត់ Password
      │                                              │ ③ បង្កើត JWT + Sign ដោយ Secret Key
      │  ④ 200 OK { accessToken: "eyJ..." }          │
      │ ◀─────────────────────────────────────────── │
      │                                              │
      │  ⑤ GET /api/profile                          │
      │     Authorization: Bearer eyJ...             │
      │ ───────────────────────────────────────────▶ │
      │                                              │ ⑥ Validate Signature
      │                                              │    + ពិនិត្យ exp, iss, aud
      │  ⑦ 200 OK { profile data }                   │
      │ ◀─────────────────────────────────────────── │
      │                                              │
      │  (Token ខុស ឬផុតកំណត់ → 401 Unauthorized)    │
“

[!NOTE]
Token ត្រូវផ្ញើក្នុង HTTP Header ឈ្មោះ Authorization ដោយមានពាក្យ Bearer នៅពីមុខ៖
Authorization: Bearer <token>


5. អនុវត្តក្នុង ASP.NET Core

ជំហានទី ១៖ ដំឡើង Package

bash
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer

ជំហានទី ២៖ កំណត់ Config ក្នុង appsettings.json

json
{
  "Jwt": {
    "Issuer": "https://api.myapp.com",
    "Audience": "https://myapp.com",
    "Key": "ប្រើ-Key-វែងយ៉ាងហោចណាស់-32-តួអក្សរ-ហើយទុកក្នុង-Secret-Manager"
  }
}
“

[!CAUTION]
កុំ Commit Secret Key ពិតប្រាកដចូល Git។ ក្នុង Production សូមប្រើ Environment Variables, User Secrets ឬ Azure Key Vault។

ជំហានទី ៣៖ Configure Authentication ក្នុង Program.cs

csharp
using System.Text;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;

var builder = WebApplication.CreateBuilder(args);

builder.Services
    .AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = builder.Configuration["Jwt:Issuer"],
            ValidAudience = builder.Configuration["Jwt:Audience"],
            IssuerSigningKey = new SymmetricSecurityKey(
                Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"]!)),
            ClockSkew = TimeSpan.FromSeconds(30)
        };
    });

builder.Services.AddAuthorization();

var app = builder.Build();

app.UseAuthentication();   // ត្រូវតែនៅមុន UseAuthorization
app.UseAuthorization();

ជំហានទី ៤៖ បង្កើត Token ពេល Login

csharp
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using Microsoft.IdentityModel.Tokens;

public class TokenService(IConfiguration config)
{
    public string CreateToken(User user)
    {
        var claims = new[]
        {
            new Claim(JwtRegisteredClaimNames.Sub, user.Id.ToString()),
            new Claim(JwtRegisteredClaimNames.Email, user.Email),
            new Claim(ClaimTypes.Role, user.Role),
            new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
        };

        var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(config["Jwt:Key"]!));
        var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

        var token = new JwtSecurityToken(
            issuer: config["Jwt:Issuer"],
            audience: config["Jwt:Audience"],
            claims: claims,
            expires: DateTime.UtcNow.AddMinutes(15),
            signingCredentials: credentials);

        return new JwtSecurityTokenHandler().WriteToken(token);
    }
}

ជំហានទី ៥៖ ការពារ Endpoint (Authentication + Authorization)

csharp
// User ណាដែល Login រួចអាចចូលបាន (Authentication)
app.MapGet("/api/profile", (ClaimsPrincipal user) =>
{
    var userId = user.FindFirstValue(ClaimTypes.NameIdentifier);
    return Results.Ok(new { userId });
})
.RequireAuthorization();

// មានតែ Role "Admin" ទេដែលអាចលុបបាន (Authorization)
app.MapDelete("/api/users/{id:int}", (int id) => Results.NoContent())
   .RequireAuthorization(policy => policy.RequireRole("Admin"));

ប្រសិនបើប្រើ Controller អ្នកអាចប្រើ Attribute [Authorize] ឬ [Authorize(Roles = "Admin")] ជំនួសវិញបាន។


6. Security Best Practices

“

[!IMPORTANT]
JWT មានសុវត្ថិភាពលុះត្រាតែអ្នកប្រើវាត្រឹមត្រូវ។ ខាងក្រោមជាចំណុចសំខាន់ៗ៖

  • ✅ កំណត់ exp ឲ្យខ្លី (ឧ. ១៥ នាទី) សម្រាប់ Access Token ហើយប្រើ Refresh Token ដើម្បីស្នើ Token ថ្មី
  • ✅ ប្រើ HTTPS ជានិច្ច — Token ដែលលួចបាន = អត្តសញ្ញាណដែលលួចបាន
  • ✅ Validate គ្រប់ចំណុច៖ Signature, exp, iss, aud
  • ✅ ប្រើ Secret Key វែង និងរឹងមាំ ឬប្រើ Asymmetric Algorithm (RS256) នៅពេលមាន Service ច្រើន
  • ✅ ពិចារណាទុក Token ក្នុង HttpOnly Cookie ដើម្បីកាត់បន្ថយហានិភ័យ XSS ជាជាងទុកក្នុង localStorage
  • ❌ កុំដាក់ទិន្នន័យសម្ងាត់ក្នុង Payload
  • ❌ កុំទទួលយក alg: none ឬអនុញ្ញាតឲ្យ Client ជ្រើសរើស Algorithm ដោយខ្លួនឯង
“

[!WARNING]
ដោយសារ JWT ជា Stateless វា មិនអាច Revoke (លុបចោល) ភ្លាមៗបានទេ មុនពេលវាផុតកំណត់។ ប្រសិនបើប្រព័ន្ធរបស់អ្នកត្រូវការ Logout ភ្លាមៗ ឬបិទ Account អ្នកអាចប្រើ Token Blacklist (ឧ. ទុក jti ក្នុង Redis) ឬកំណត់ exp ឲ្យខ្លី។


7. JWT ទល់នឹង Session-based Authentication

លក្ខណៈ Session (Cookie) JWT
កន្លែងទុកទិន្នន័យ Server (Memory / Redis / DB) ក្នុង Token ខ្លួនឯង
Scalability ត្រូវការ Shared Session Store ងាយ Scale (Stateless)
Revoke ភ្លាមៗ ✅ ងាយ ⚠️ ពិបាក
Mobile App / Microservices មិនសូវស័ក្តិសម ✅ ស័ក្តិសមណាស់
ទំហំ Request តូច (Session ID) ធំជាង (Token ពេញ)
“

[!TIP]
គ្មានវិធីណាល្អជាងគេដាច់ខាតទេ។ សម្រាប់ Web App តែមួយធម្មតា Session នៅតែល្អណាស់។ JWT ភ្លឺស្វាងនៅពេលអ្នកមាន SPA, Mobile App ឬ Microservices ច្រើនដែលត្រូវផ្ទៀងផ្ទាត់ User ដូចគ្នា។


8. សង្ខេប

  • Authentication = អ្នកជានរណា | Authorization = អ្នកមានសិទ្ធិធ្វើអ្វី
  • JWT មាន ៣ ផ្នែក៖ Header (Algorithm), Payload (Claims), Signature (ការពារការកែប្រែ)
  • Payload អាចអានបាន ដោយអ្នកណាក៏បាន — Signature គ្រាន់តែការពារកុំឲ្យ កែប្រែ ប៉ុណ្ណោះ
  • ក្នុង ASP.NET Core ប្រើ AddJwtBearer() + RequireAuthorization() គឺអាចការពារ API បានយ៉ាងងាយ
  • កំណត់ exp ខ្លី ប្រើ HTTPS និង Refresh Token ដើម្បីសុវត្ថិភាពល្អបំផុត

💬 សំណួរសម្រាប់អ្នក៖ តើ Project របស់អ្នកប្រើ JWT ឬ Session? ហើយអ្នកទុក Token នៅកន្លែងណា? ចែករំលែកនៅក្នុង Comment ខាងក្រោម!

📌 អត្ថបទបន្ទាប់៖ Refresh Token Rotation ក្នុង ASP.NET Core — របៀបធ្វើឲ្យ User Login យូរដោយមិនបាត់បង់សុវត្ថិភាព

ចូលរួមការពិភាក្សា
0 មតិយោបល់រហូតមកដល់ពេលនេះ - ចូលចិត្ត ផ្ដល់មតិ និងចែករំលែករបស់អ្នកនៅលើ Cambostack។
បើកក្នុង Cambostack