【问题标题】:How can I pass the authenticated User Id to the class library project in asp.net core via DI?如何通过 DI 将经过身份验证的用户 ID 传递给 asp.net 核心中的类库项目?
【发布时间】:2020-04-04 21:25:44
【问题描述】:

我有一个 NLayers 应用程序:

  • asp.net core mvc
  • asp.net web api

还有我的一些类库:

  • 数据层
  • 域类
  • 型号
  • 服务

这是我在 ServicesLayer 中的 BaseService:

public abstract partial class BaseService 
{
   protected BaseService(AppDbContext dbContext
                        , UserManager<MyApplicationUser> userManager
                        , int authenticatedUserId)
   {
       DbContext = dbContext;
       AuthenticatedUserId = authenticatedUserId;
       MyUserManager = userManager;

       Init();
  }

  public AppDbContext DbContext { get; }
  protected UserManager<MyApplicationUser> MyUserManager;
  public string AuthenticatedUserId { get; }

  protected virtual void Init()
  {
    // 
  }

  ...

}

和我的儿童服务班之一:

public class BookService :BaseService
{
   public BookService(AppDbContext dbContext
       , UserManager<MyApplicationUser> userManager 
        , int authenticatedUserId)

        :base(dbContext,userManager, authenticatedUserId)
    {

    }
}

我想在我的服务(类库)中访问经过身份验证的用户 ID(来自 Asp net core)。如何通过 DI 或其他方式传递它?

根据@Frank 的建议更新:

public class CommonServicesContainer
{
    public AppDbContext DbContext { get; set; }
    public AppUserManager UserManager { get; set; }
    public int AuthenticatedUserId{ get; set; }

    public CommonServicesContainer(AppDbContext appDbContext, AppUserManager userManager, string authenticatedUserId)
    {
        DbContext = dbContext;
        UserManager = userManager;
        AuthenticatedUserId = autheticatedUserId;
    }
}

我的创业:

        services.AddScoped<AppDbContext>();
        services.AddScoped<AppUserManager>();

        services.AddScoped(x =>
        {
            var authenticatedUserId = x.GetRequiredService<IHttpContextAccessor>().HttpContext.User.Identity.Name;

            return new CommonServicesContainer(x.GetRequiredService<AppDbContext>()
                                         , x.GetRequiredService<AppUserManager>()
                                         , authenticatedUserId);
        });

帐户控制器:

private readonly CommonServicesContainer _commonServicesContainer;

public AccountController(CommonServicesContainer commonServicesContainer)
{
    _commonServicesContainer = commonServicesContainer;

    // ...
}


[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login(LoginInputModel model)
{
   // ... 
   if(ModelState.IsValid)
   {
                var isValid = await _usersService.AreCredentialsValidAsync(model.Username, model.Password);

   if(isValid)
   {
       var foundUser = await _usersService.GetByUserNameAsync(model.Username);

                        await HttpContext.SignInAsync(
                                        foundUser.SubjectId,                         
                                        foundUser.UserName);

                        //_commonServicesContainer.AuthenticatedUserId = foundUser.Id;
                        // ...

   }
   // ...
}

【问题讨论】:

  • 我看到我可以将 IHttpContextAccessor 注入到我的类中,但是我必须将它注入到所有子类的构造函数中,并且它变得非常拥挤

标签: asp.net-core dependency-injection


【解决方案1】:

您可以通过将 AuthenticatedUser 类型注册为 AddScoped 来做到这一点。

class AuthenticatedUser {
  public int? UserId {get;set;}
  public bool IsAuthenticated => int.HasValue;
}

在您的 AspNetCore 项目的 Startup.cs 中:

public IServiceProvider ConfigureServices(IServiceCollection services) {
   ...
   services.AddScoped<AuthenticatedUser>();
   ...
}

在您进行身份验证的地方,您会获得 AuthenticatedUser 并设置 UserId。

由于AuthenticatedUser 被添加为作用域,它充当特定httprequest 作用域的全局(相同实例)。所以所有.GetService&lt;AuthenticatedUser&gt; / .GetRequiredService&lt;AuthenticatedUser&gt; 都将具有相同的实例 - 在相同的范围内。

每个 http 请求都有自己的范围,因此也有自己的AuthenticatedUser。

当用户通过身份验证时,使用 AspNetCore Identity,您可以通过以下方式找到AspNetUsers Id:

if( httpContext.User.Identity.IsAuthenticated ) {
  var userIdClaim = httpContext.User.Claims.SingleOrDefault(c => c.Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier");
  var aspNetUsersId = userIdClaim?.Value ?? 0;
}

这可以作为中间件完成,然后设置AuthenticatedUser.UserId。

【讨论】:

  • 谢谢,但我该怎么做呢? “在您进行身份验证的地方,您会获得 AuthenticatedUser 并设置 UserId。”正如你所说,我在Startup.cs 中注入了类,然后我在AccountController.Login 方法中设置了userId,在await HttpContext.SignInAsync() 之后,但我在ServiceLayer 中得到了空值
  • 您必须在每个请求上设置AuthenticatedUser.UserId = x,因为它将是一个新的范围/实例。您通常使用设置它的中间件来执行此操作。您如何获得authenticatedUserId? - 显示代码。
  • 是用户登录(用户名/密码)AccountController POSTLogin,还是对后端的每个请求都进行了?
  • 这是我在Controller 中的User/Password signIn method,并且只在用户登录时执行一次,然后我想在我的类库中拥有Authenticated UserId
  • 好的,您必须验证HttpContext.User.Identity.IsAuthenticated 以确保用户已通过身份验证。其次是认为HttpContext.User.Identity.Name 将包含用户的电子邮件!我会更新我的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-07-06
  • 2018-04-06
  • 2020-01-17
  • 2018-08-31
  • 2019-10-28
  • 2020-01-13
  • 2020-11-15
相关资源
最近更新 更多