Session-Based authentication

เดิมทีแอปพลิเคชันของเราใช้ JWT (JSON Web Token) สำหรับการยืนยันตัวตน โดยจะแบ่งเป็น Access Token และ Refresh Token ซึ่งจะถูกส่งไปให้ฝั่ง Client เพื่อเก็บไว้ใน Local Storage ของเบราว์เซอร์

เพื่อเพิ่มความปลอดภัยและลดความเสี่ยงจากการโจมตีแบบ XSS (Cross-Site Scripting) เราได้เปลี่ยนระบบมาใช้ Session-based Authentication แทน โดยข้อมูล session จะถูกเก็บใน HTTP-only Cookie ซึ่งสามารถป้องกันไม่ให้สคริปต์ฝั่ง Client เข้าถึงได้โดยตรง ทำให้การจัดการ session มีความปลอดภัยมากขึ้น

สรุปการเปลี่ยนแปลงสำคัญ:

  • เลิกใช้ JWT token ใน Local Storage
  • ใช้ session-based authentication แทน
  • ข้อมูล session ถูกเก็บใน HTTP-only Cookie

Registration

1. ลงทะเบียน Authentication Schema

ลงทะเบียน Schema session เพื่อให้ Policy-base เข้าถึง session และตรวจสอบสิทธิได้

builder.Services.AddAuth(builder.Configuration);

2. ลงทะเบียน Cache

ลงทะเบียน Cache เพื่อจัดเก็บ Session ลง cache เพื่อ performance ในการตรวจสอบสิทธิ์ โดย defaul จะใช้ IDistributedCache ในการเรียกใช้และจัดเก็บ Session ซึ่งจะเก็บ Session ใน Memory instance ของ service ที่รันอยู่ แต่หาก เป็น microservices คุณสามารถใส่ connection redis เพื่อใช้ redis แทนเพื่อให้เหมาะสมกับสถานการณ์ของคุณ

// Program.cs
builder.Services.AddCache(builder.Configuration.GetSection("Redis")["ConnectionString"]);

// AddCache
public static IServiceCollection AddCache(this IServiceCollection services, string? connectionString)
{
    if (string.IsNullOrEmpty(connectionString))
    {
        services.AddDistributedMemoryCache();
    }
    else
    {
        services.AddStackExchangeRedisCache(option =>
        {
            option.Configuration = connectionString;
        });
    }

    return services;
}

3. ลงทะเบียน SessionService

ลงทะเบียน SessionService สำหรับจัดการ Session ของ user

builder.Services.AddScoped<SessionService>();

การใช้งาน

จากนั้น inject SessionService เข้า class ที่ต้องการใช้งานผ่าน constructor

public class MyService
{
    private readonly SessionService _session;

    public MyService(SessionService session)
    {
        _session = session;
    }
}

Methods

NameReturnsDescription
CreateSession(String, SessionData, TimeSpan)voidสร้าง session ใหม่และบันทึกลงใน cache
GetSession(String)SessionData?ดึงข้อมูล session จาก sessionId
RefreshSession(String, SessionData, TimeSpan)voidอัปเดตข้อมูลและต่ออายุ session
RemoveSession(String)voidลบ session ออกจาก cache
RotateSession(String, SessionData, TimeSpan, TimeSpan)string?สร้าง session ใหม่และยกเลิกตัวเดิม

Session Data

ข้อมูลที่เก็บใน session ประกอบด้วย

FieldDescription
UserIdID ของผู้ใช้
Roleรายการ role ของผู้ใช้
Permissionรายการ permission ในรูปแบบ roleId:functionId = view,edit
ExpiresAtเวลาหมดอายุของ session
IsRotatedบอกว่า session นี้ถูก rotate ไปแล้วหรือยัง