2. Security Context
Hãy đi sâu vào Security Context trong Spring Security. Tôi sẽ giải thích về SecurityContextHolder
, các chiến lược lưu trữ (ThreadLocal
và InheritableThreadLocal
), và cách thông tin người dùng được truyền qua các request.
1. SecurityContextHolder và các chiến lược lưu trữ
a. SecurityContextHolder là gì?
Định nghĩa:
SecurityContextHolder
là một lớp tĩnh trong Spring Security, đóng vai trò như một "người giữ" trung tâm để lưu trữ và truy xuất thông tin bảo mật (security context) của request hiện tại.Nó chứa
SecurityContext
, mà trong đó lưu trữ đối tượngAuthentication
– thông tin về người dùng đã xác thực (username, roles, v.v.).
Vai trò:
Cho phép truy cập thông tin người dùng từ bất kỳ đâu trong ứng dụng (controller, service, v.v.) mà không cần truyền tham số thủ công.
Ví dụ cơ bản:
b. Các chiến lược lưu trữ
SecurityContextHolder
hỗ trợ nhiều chiến lược lưu trữ để quản lýSecurityContext
giữa các thread và request. Các chiến lược này được cấu hình quaSecurityContextHolder.setStrategyName()
hoặc mặc định trong Spring Security.
MODE_THREADLOCAL
(ThreadLocal):Mô tả:
Sử dụng
ThreadLocal
để lưu trữSecurityContext
riêng biệt cho mỗi thread.Mỗi request trong ứng dụng web thường được xử lý bởi một thread riêng, nên
SecurityContext
chỉ tồn tại trong phạm vi thread đó.
Ưu điểm:
Đơn giản, hiệu quả cho ứng dụng web truyền thống.
Không bị rò rỉ thông tin giữa các request.
Nhược điểm:
Không hoạt động tốt với các tác vụ bất đồng bộ (async) hoặc thread pool, vì
ThreadLocal
không được truyền sang thread con.
Mặc định: Đây là chiến lược mặc định của Spring Security.
Ví dụ:
MODE_INHERITABLETHREADLOCAL
(InheritableThreadLocal):Mô tả:
Sử dụng
InheritableThreadLocal
để lưu trữSecurityContext
, cho phép thread con kế thừa context từ thread cha.
Ưu điểm:
Hữu ích trong ứng dụng có xử lý bất đồng bộ hoặc thread pool (như
@Async
trong Spring), vì thông tin bảo mật được truyền sang thread con.
Nhược điểm:
Có thể gây rò rỉ thông tin nếu thread con được tái sử dụng cho request khác.
Ví dụ:
Ứng dụng thực tế:
Khi dùng
@Async
:
MODE_GLOBAL
:Mô tả:
Lưu trữ
SecurityContext
trong một biến tĩnh toàn cục, chung cho tất cả thread.
Ưu điểm:
Đơn giản, dùng trong ứng dụng không yêu cầu đa luồng.
Nhược điểm:
Không an toàn trong ứng dụng web, vì tất cả request chia sẻ cùng context.
Ít dùng: Chủ yếu cho mục đích test hoặc ứng dụng đơn luồng.
Cấu hình chiến lược:
Trong Spring Boot, thêm vào
application.properties
:Hoặc trong mã:
2. Cách thông tin người dùng được truyền qua các request
Quy trình truyền thông tin:
Xác thực ban đầu:
Khi người dùng đăng nhập (qua
UsernamePasswordAuthenticationFilter
chẳng hạn), Spring Security tạo đối tượngAuthentication
và đặt vàoSecurityContext
.Ví dụ:
Lưu trữ giữa các request:
SecurityContextPersistenceFilter
(filter đầu tiên trong Filter Chain) chịu trách nhiệm:Lấy
SecurityContext
từHttpSession
(nếu có) ở đầu request.Lưu lại
SecurityContext
vàoHttpSession
ở cuối request (trước khi response được gửi).
Điều này đảm bảo thông tin người dùng (như
Authentication
) được duy trì qua nhiều request mà không cần xác thực lại.
Truy xuất trong ứng dụng:
Bất kỳ đâu trong mã, bạn có thể lấy thông tin:
Xóa khi đăng xuất:
LogoutFilter
xóaSecurityContext
khỏiHttpSession
vàSecurityContextHolder
khi người dùng đăng xuất.
Cơ chế lưu trữ với HttpSession:
Mặc định,
SecurityContext
được lưu trongHttpSession
dưới keySPRING_SECURITY_CONTEXT
.Khi request mới đến,
SecurityContextPersistenceFilter
khôi phục context từ session, đặt vàoSecurityContextHolder
để sử dụng trong thread hiện tại.
Trường hợp đặc biệt: Stateless (JWT):
Nếu dùng
SessionCreationPolicy.STATELESS
(ví dụ với JWT):SecurityContext
không được lưu trong session. Thay vào đó, thông tin người dùng được lấy từ token trong mỗi request (qua custom filter nhưJwtAuthenticationFilter
), vàSecurityContextHolder
chỉ giữ context trong phạm vi request đó.
Tóm tắt
SecurityContextHolder:
Lớp trung tâm để lưu trữ và truy xuất
SecurityContext
.Chiến lược lưu trữ:
ThreadLocal
: Mặc định, phù hợp với ứng dụng web cơ bản.InheritableThreadLocal
: Hỗ trợ truyền context sang thread con (async).Global
: Ít dùng, không an toàn cho web.
Truyền thông tin qua request:
Thông qua
HttpSession
vàSecurityContextPersistenceFilter
trong ứng dụng stateful.Qua token và custom filter trong ứng dụng stateless.
Last updated