Tôi phải nói rằng tôi khá ngạc nhiên rằng HttpContext là null bên trong hàm tạo. Tôi chắc rằng đó là vì lý do hiệu suất. Đã xác nhận rằng việc sử dụng IPrincipal
như mô tả bên dưới sẽ đưa nó vào hàm tạo. Về cơ bản, nó hoạt động giống như câu trả lời được chấp nhận, nhưng theo một cách giao diện hơn.
Đối với bất kỳ ai tìm thấy câu hỏi này đang tìm kiếm câu trả lời cho câu trả lời chung chung "Làm thế nào để có được người dùng hiện tại?" bạn chỉ có thể truy cập User
trực tiếp từ Controller.User
. Nhưng bạn chỉ có thể thực hiện điều này bên trong các phương thức hành động (tôi giả sử vì bộ điều khiển không chỉ chạy với HttpContexts và vì lý do hiệu suất).
Tuy nhiên - nếu bạn cần nó trong hàm tạo (như OP đã làm) hoặc cần tạo các đối tượng có thể tiêm khác mà cần người dùng hiện tại thì cách tiếp cận dưới đây là tốt hơn:
Tiêm IPrincipal để có được người dùng
Lần đầu gặp gỡ IPrincipal
vàIIdentity
public interface IPrincipal
{
IIdentity Identity { get; }
bool IsInRole(string role);
}
public interface IIdentity
{
string AuthenticationType { get; }
bool IsAuthenticated { get; }
string Name { get; }
}
IPrincipal
và IIdentity
đại diện cho người dùng và tên người dùng. Wikipedia sẽ an ủi bạn nếu 'Hiệu trưởng' nghe có vẻ kỳ quặc .
Quan trọng là phải nhận ra rằng cho dù bạn nhận được nó từ IHttpContextAccessor.HttpContext.User
, ControllerBase.User
hoặc ControllerBase.HttpContext.User
bạn đang nhận được một đối tượng mà là đảm bảo được một ClaimsPrincipal
đối tượng mà cụIPrincipal
.
Không có loại Người dùng nào khác mà ASP.NET sử dụng User
ngay bây giờ, (nhưng điều đó không có nghĩa là một cái gì đó khác không thể thực hiện IPrincipal
).
Vì vậy, nếu bạn có thứ gì đó phụ thuộc vào 'tên người dùng hiện tại' mà bạn muốn tiêm, bạn nên tiêm IPrincipal
và chắc chắn là không IHttpContextAccessor
.
Quan trọng: Đừng lãng phí thời gian tiêm IPrincipal
trực tiếp vào bộ điều khiển hoặc phương pháp hành động của bạn - điều đó là vô nghĩa vì User
bạn đã có sẵn ở đó.
Trong startup.cs
:
// Inject IPrincipal
services.AddTransient<IPrincipal>(provider => provider.GetService<IHttpContextAccessor>().HttpContext.User);
Sau đó, trong đối tượng DI của bạn cần người dùng mà bạn chỉ cần đưa vào IPrincipal
để có được người dùng hiện tại.
Điều quan trọng nhất ở đây là nếu bạn đang thực hiện các bài kiểm tra đơn vị, bạn không cần phải gửi một HttpContext
, mà chỉ cần mô phỏng một cái gì đó đại diện cho IPrincipal
cái có thể ClaimsPrincipal
.
Một điều quan trọng nữa mà tôi không chắc 100%. Nếu bạn cần truy cập các xác nhận quyền sở hữu thực tế từ ClaimsPrincipal
bạn cần truyền IPrincipal
đến ClaimsPrincipal
. Điều này là tốt vì chúng tôi biết 100% rằng trong thời gian chạy nó thuộc loại đó (vì đó là cái gì HttpContext.User
). Tôi thực sự thích chỉ làm điều này trong hàm tạo vì tôi đã biết chắc chắn bất kỳ IPrincipal
sẽ là a ClaimsPrincipal
.
Nếu bạn đang chế nhạo, chỉ cần tạo ClaimsPrincipal
trực tiếp và chuyển nó cho bất cứ điều gì cần thiết IPrincipal
.
Chính xác tại sao không có giao diện cho IClaimsPrincipal
tôi không chắc chắn. Tôi cho rằng MS đã quyết định rằng đó ClaimsPrincipal
chỉ là một 'bộ sưu tập' chuyên biệt không đảm bảo giao diện.