Cách lấy người dùng hiện tại trong lõi asp.net


129

Tôi muốn có được người dùng hiện tại để lấy thông tin của người dùng chẳng hạn như email. Nhưng tôi không thể làm điều đó trong lõi asp.net. Tôi rất bối rối Đây là mã của tôi.

HttpContextgần như là null trong hàm tạo của bộ điều khiển. Thật không tốt khi có được một người dùng trong mỗi hành động. Tôi muốn lấy thông tin của người dùng một lần và đặt chúng thành ViewData;

public DashboardController()
{
    var user = HttpContext.User.GetUserId();
}

5
Sử dụng với MVC hoặc Web APi?
Tushar

Câu trả lời:


172
User.FindFirst(ClaimTypes.NameIdentifier).Value

CHỈNH SỬA cho hàm tạo

Mã dưới đây hoạt động:

public Controller(IHttpContextAccessor httpContextAccessor)
{
    var userId = httpContextAccessor.HttpContext.User.FindFirst(ClaimTypes.NameIdentifier).Value 
}

Chỉnh sửa cho RTM

Bạn nên đăng ký IHttpContextAccessor:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddHttpContextAccessor();
    }

2
nó hoạt động trong các hành động. nhưng tôi muốn sử dụng trong phương thức khởi tạo của bộ điều khiển.
Mehran Hafizi

3
nó có thể sử dụng điều này trong các lớp học không?
Mehran Hafizi

5
ClaimTypes.NameIdentifiercung cấp id người dùng hiện tại và ClaimTypes.Namecung cấp tên người dùng.
Nikolay Kostov

3
Ai có thể cho tôi biết điều gì là sai với UserPrincipal.Current.Name?
tipura

2
@ademcaglin Vì một số lý do Người dùng quay lại nulltrong trường hợp của tôi? Tôi đang sử dụng .Net core 2.1 Web apimặc dù.
Sruthi Varghese

55

Cách đơn giản mà hoạt động và tôi đã kiểm tra.

private readonly UserManager<IdentityUser> _userManager;
public CompetitionsController(UserManager<IdentityUser> userManager)
{
    _userManager = userManager;
}

var user = await _userManager.GetUserAsync(HttpContext.User);

thì bạn có thể tất cả các thuộc tính của biến này như thế nào user.Email. Tôi hy vọng điều này sẽ giúp một ai đó.

Chỉnh sửa :

Đó là một điều có vẻ đơn giản nhưng hơi phức tạp gây ra các loại hệ thống xác thực khác nhau trong ASP.NET Core. Tôi cập nhật vì một số người đang nhận được null.

Đối với Xác thực JWT (Đã kiểm tra trên ASP.NET Core v3.0.0-preview7):

var email = HttpContext.User.Claims.FirstOrDefault(c => c.Type == "sub")?.Value;

var user = await _userManager.FindByEmailAsync(email);

1
hoạt động tuyệt vời đối với tôi trong một bộ điều khiển trong asp.net Lõi 2.0
jmdon

2
_userManager là gì?
NullVoxPopuli

6
Trong ASP.NET Core Identity, User Manager là một dịch vụ được cung cấp bởi Dependency Inject to Create Users. Xem tài liệu để biết thêm thông tin:
Ahmad

2
Làm cách nào để đạt được điều này trong một phương pháp không đồng bộ?
T3.0

Đối với tôi là trả về null. Tại sao?
Alberto Cláudio Mandlate,

22

Có một cách khác để thu hút người dùng hiện tại trong Asp.NET Core - và tôi nghĩ tôi đã thấy nó ở đâu đó ở đây, trên SO ^^

// Stores UserManager
private readonly UserManager<ApplicationUser> _manager; 

// Inject UserManager using dependency injection.
// Works only if you choose "Individual user accounts" during project creation.
public DemoController(UserManager<ApplicationUser> manager)  
{  
    _manager = manager;  
}

// You can also just take part after return and use it in async methods.
private async Task<ApplicationUser> GetCurrentUser()  
{  
    return await _manager.GetUserAsync(HttpContext.User);  
}  

// Generic demo method.
public async Task DemoMethod()  
{  
    var user = await GetCurrentUser(); 
    string userEmail = user.Email; // Here you gets user email 
    string userId = user.Id;
}  

Mã đó đi đến bộ điều khiển có tên DemoController. Sẽ không hoạt động nếu không có cả hai chờ đợi (sẽ không biên dịch);)


Điều này yêu cầu sử dụng Danh tính
Fraze

1
ApplicationUser là gì?
Mike

ApplicationUser thường được kế thừa từ IdentityUser nên nó có thể được mở rộng với các thuộc tính bổ sung, v.v.
Corgalore

20

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 IPrincipalnhư 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 Usertrự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ỡ IPrincipalIIdentity

public interface IPrincipal
{
    IIdentity Identity { get; }
    bool IsInRole(string role);
}

public interface IIdentity
{
    string AuthenticationType { get; }
    bool IsAuthenticated { get; }
    string Name { get; }
}

IPrincipalIIdentityđạ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.Userhoặc ControllerBase.HttpContext.Userbạ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 Userngay 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 IPrincipalvà chắc chắn là không IHttpContextAccessor.

Quan trọng: Đừng lãng phí thời gian tiêm IPrincipaltrự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ì Userbạ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ừ ClaimsPrincipalbạ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 ClaimsPrincipaltrự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 IClaimsPrincipaltôi không chắc chắn. Tôi cho rằng MS đã quyết định rằng đó ClaimsPrincipalchỉ là một 'bộ sưu tập' chuyên biệt không đảm bảo giao diện.


2
Điều này cho phép bạn đưa người dùng hiện tại vào bất kỳ đâu trong ứng dụng của bạn, câu trả lời tuyệt vời!
Machado

1
Điều này không hiệu quả. Tôi luôn luôn được nulltiêm IPrincipal. Tôi cũng cần thêm dịch vụ tạm thời dưới dạng …GetService<IHttpContextAccessor>()?.HttpContext.User…(với ?) vì nếu không nó sẽ bị lỗi (GetService trả về null).
ygoe

Bạn chỉ có thể làm services.AddTransient(provider => provider.GetService<IHttpContextAccessor>().HttpContext.User);như HttpContext. Người dùng là một ClaimsPrincipal.
Jay Zelos

18

Có vẻ như tính đến thời điểm hiện tại (tháng 4 năm 2017) các hoạt động sau:

public string LoggedInUser => User.Identity.Name;

Ít nhất là trong một Controller


4
Bạn không thể chuyển đổi hoàn toàn kiểu 'System.Security.Principal.IIdentity' thành 'string'.
Anthony Huang

3
string LoggedInUser = User.Identity.Name;
Alic W

5
Là một người chưa từng thấy =>toán tử được sử dụng như vậy trước đây, nó được gọi là "Định nghĩa cơ thể biểu thức" và được mô tả trong tài liệu này . Đề phòng những người trong tương lai như tôi đang băn khoăn.
Nathan Clement

Mã của bạn không thể biên dịch trước khi chỉnh sửa, do không có chuyển đổi từ IIdentitythành string, như cũng đã nêu trong nhận xét trên cùng. Chỉnh sửa chỉ đơn giản là sửa điều đó. Tôi cũng không chắc bạn đã đưa ra kết luận như thế nào (đặc biệt vì điểm "biên tập viên" chỉ được trao cho người dùng dưới 2k danh tiếng).
fuglede

9

Có lẽ tôi không thấy câu trả lời, nhưng đây là cách tôi làm.

  1. .Net Core -> Thuộc tính -> khởi chạySettings.json

Bạn cần phải thay đổi các giá trị này

"windowsAuthentication": true, // needs to be true
"anonymousAuthentication": false,  // needs to be false 

Startup.cs -> ConfigureServices (...)

services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

Bộ điều khiển MVC hoặc Web Api

private readonly IHttpContextAccessor _httpContextAccessor;
//constructor then
_httpContextAccessor = httpContextAccessor;

Phương pháp điều khiển:

string userName = _httpContextAccessor.HttpContext.User.Identity.Name;

Kết quả là userName, ví dụ = Tên miền \ tên người dùng


4

Vấn đề của tôi là truy cập Người dùng đã đăng nhập dưới dạng một đối tượng trong tệp cshtml. Xem xét bạn muốn người dùng trong ViewData, phương pháp này có thể hữu ích:

Trong tệp cshtml

@using Microsoft.AspNetCore.Identity
@inject UserManager<ApplicationUser> UserManager

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>
    @UserManager.FindByNameAsync(UserManager.GetUserName(User)).Result.Email
    </title>
  </head>
  <body>

  </body>
</html>

Bất kỳ ý tưởng nào về cách bạn có thể tải thuộc tính điều hướng (Tên công ty của thuộc tính điều hướng công ty trên lớp ApplicationUser của tôi). Không thấy cách để bao gồm các thuộc tính điều hướng.
Hunter Nelson

1

Ngoài các câu trả lời hiện có, tôi muốn thêm rằng bạn cũng có thể có một phiên bản lớp có sẵn trên toàn ứng dụng chứa dữ liệu liên quan đến người dùng như UserIDv.v.

Nó có thể hữu ích cho việc tái cấu trúc, ví dụ: bạn không muốn tìm nạp UserIDtrong mọi hành động của bộ điều khiển và khai báo một UserIDtham số bổ sung trong mọi phương thức liên quan đến Lớp dịch vụ.

Tôi đã thực hiện một nghiên cứu và đây là bài đăng của tôi .

Bạn chỉ cần mở rộng lớp của mình mà bạn có được DbContextbằng cách thêm thuộc UserIdtính (hoặc triển khai một tùy chỉnhSession lớp có thuộc tính này).

Ở cấp độ bộ lọc, bạn có thể tìm nạp cá thể lớp của mình và đặt UserIdgiá trị.

Sau đó, bất cứ nơi nào bạn đưa cá thể của mình vào - nó sẽ có dữ liệu cần thiết (thời gian tồn tại phải theo yêu cầu , vì vậy bạn đăng ký nó bằng AddScopedphương pháp).

Ví dụ làm việc:

public class AppInitializationFilter : IAsyncActionFilter
{
    private DBContextWithUserAuditing _dbContext;

    public AppInitializationFilter(
        DBContextWithUserAuditing dbContext
        )
    {
        _dbContext = dbContext;
    }

    public async Task OnActionExecutionAsync(
        ActionExecutingContext context,
        ActionExecutionDelegate next
        )
    {
        string userId = null;
        int? tenantId = null;

        var claimsIdentity = (ClaimsIdentity)context.HttpContext.User.Identity;

        var userIdClaim = claimsIdentity.Claims.SingleOrDefault(c => c.Type == ClaimTypes.NameIdentifier);
        if (userIdClaim != null)
        {
            userId = userIdClaim.Value;
        }

        var tenantIdClaim = claimsIdentity.Claims.SingleOrDefault(c => c.Type == CustomClaims.TenantId);
        if (tenantIdClaim != null)
        {
            tenantId = !string.IsNullOrEmpty(tenantIdClaim.Value) ? int.Parse(tenantIdClaim.Value) : (int?)null;
        }

        _dbContext.UserId = userId;
        _dbContext.TenantId = tenantId;

        var resultContext = await next();
    }
}

Để biết thêm thông tin, hãy xem câu trả lời của tôi .


0

Lấy IdentityUsercũng sẽ hiệu quả. Đây là đối tượng người dùng hiện tại và tất cả các giá trị của người dùng có thể được truy xuất.

private readonly UserManager<IdentityUser> _userManager;
public yourController(UserManager<IdentityUser> userManager)
{
    _userManager = userManager;
}

var user = await _userManager.GetUserAsync(HttpContext.User);

0

Nếu bạn đang sử dụng Identity được quét và sử dụng Asp.net Core 2.2+, bạn có thể truy cập người dùng hiện tại từ chế độ xem như sau:

@using Microsoft.AspNetCore.Identity
@inject SignInManager<IdentityUser> SignInManager
@inject UserManager<IdentityUser> UserManager

 @if (SignInManager.IsSignedIn(User))
    {
        <p>Hello @User.Identity.Name!</p>
    }
    else
    {
        <p>You're not signed in!</p>
    }

https://docs.microsoft.com/en-us/aspnet/core/security/authentication/identity?view=aspnetcore-2.2&tabs=visual-studio


0

Đây là câu hỏi cũ nhưng trường hợp của tôi cho thấy rằng trường hợp của tôi không được thảo luận ở đây.

Tôi thích nhất câu trả lời của Simon_Weaver ( https://stackoverflow.com/a/54411397/2903893 ). Anh ấy giải thích chi tiết cách lấy tên người dùng bằng IPrincipal và IIdentity. Câu trả lời này là hoàn toàn chính xác và tôi khuyên bạn nên sử dụng cách tiếp cận này. Tuy nhiên, trong quá trình gỡ lỗi, tôi gặp phải sự cố khi ASP.NET KHÔNG thể điền nguyên tắc dịch vụ đúng cách . (hay nói cách khác, IPrincipal.Identity.Name là null)

Rõ ràng là để có được tên người dùng, khuôn khổ MVC nên lấy nó từ đâu đó. Trong thế giới .NET, ASP.NET hoặc ASP.NET Core đang sử dụng phần mềm trung gian Open ID Connect. Trong trường hợp đơn giản, các ứng dụng web xác thực người dùng trong trình duyệt web. Trong trường hợp này, ứng dụng web hướng trình duyệt của người dùng đăng nhập vào Azure AD. Azure AD trả về phản hồi đăng nhập thông qua trình duyệt của người dùng, chứa các xác nhận quyền sở hữu về người dùng trong mã thông báo bảo mật. Để làm cho nó hoạt động trong mã cho ứng dụng của bạn, bạn sẽ cần cung cấp quyền hạn mà bạn ủy quyền cho ứng dụng web đăng nhập. Khi bạn triển khai ứng dụng web của mình với Dịch vụ Azure, tình huống phổ biến để đáp ứng yêu cầu này là định cấu hình ứng dụng web: "Dịch vụ ứng dụng" -> Ứng dụng của bạn -> phiến "Xác thực / Ủy quyền" -> "Xác thực dịch vụ ứng dụng" = "Bật"https://github.com/Huachao/azure-content/blob/master/articles/app-service-api/app-service-api-authentication.md ). Tôi tin rằng (đây là phỏng đoán đã được học của tôi) rằng trong quá trình này, trình hướng dẫn điều chỉnh cấu hình web "gốc" của ứng dụng web này bằng cách thêm các cài đặt tương tự mà tôi hiển thị trong các đoạn sau. Về cơ bản, vấn đề tại sao cách tiếp cận này KHÔNG hoạt động trong ASP.NET Core là do cấu hình máy "mẹ" bị webconfig bỏ qua. (Điều này không chắc chắn 100%, tôi chỉ đưa ra lời giải thích tốt nhất mà tôi có). Vì vậy, để meke hoạt động, bạn cần thiết lập thủ công điều này trong ứng dụng của mình.

Đây là bài viết giải thích cách thiết lập nhiều ứng dụng của bạn để sử dụng Azure AD. https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2/tree/aspnetcore2-2

Bước 1: Đăng ký mẫu với người thuê Azure AD của bạn. (đó là điều hiển nhiên, không muốn tốn thời gian của tôi để giải thích).

Bước 2: Trong tệp appsettings.json: thay thế giá trị ClientID bằng ID ứng dụng từ ứng dụng bạn đã đăng ký trong cổng Đăng ký ứng dụng ở Bước 1. thay thế giá trị TenantId bằng chung

Bước 3: Mở tệp Startup.cs và trong phương thức ConfigureServices, sau dòng chứa .AddAzureAD, hãy chèn mã sau để cho phép ứng dụng của bạn đăng nhập người dùng bằng điểm cuối Azure AD v2.0, đó là cả Cơ quan và Trường học và Tài khoản cá nhân của Microsoft.

services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
{
    options.Authority = options.Authority + "/v2.0/";
    options.TokenValidationParameters.ValidateIssuer = false;
});

Tóm tắt : Tôi đã chỉ ra một vấn đề khác có thể xảy ra có thể do lỗi mà người khởi động chủ đề được giải thích. Lý do của sự cố này là thiếu cấu hình cho Azure AD (Phần mềm trung gian ID mở). Để giải quyết vấn đề này, tôi đề xuất thiết lập "Xác thực / Ủy quyền" theo cách thủ công. Tổng quan ngắn gọn về cách thiết lập điều này được thêm vào.


0

Hầu hết các câu trả lời cho thấy cách xử lý tốt nhất HttpContexttừ tài liệu, đây cũng là điều tôi đã làm.

Tôi muốn đề cập rằng bạn sẽ muốn kiểm tra cài đặt dự án khi gỡ lỗi, mặc định là Enable Anonymous Authentication = true.


-1

Tôi đã có giải pháp của mình

var claim = HttpContext.User.CurrentUserID();

public static class XYZ
{
    public static int CurrentUserID(this ClaimsPrincipal claim)
    {
        var userID = claimsPrincipal.Claims.ToList().Find(r => r.Type == 
         "UserID").Value;
        return Convert.ToInt32(userID);
    }
    public static string CurrentUserRole(this ClaimsPrincipal claim)
    {
        var role = claimsPrincipal.Claims.ToList().Find(r => r.Type == 
        "Role").Value;
        return role;
    }
}

1
Mặc dù mã này có thể trả lời câu hỏi, nhưng việc cung cấp thêm ngữ cảnh về cách thứclý do nó giải quyết vấn đề sẽ cải thiện giá trị lâu dài của câu trả lời.
Alexander
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.