简体   繁体   English

如何注入 UserManager 和 SignInManager

[英]How to inject UserManager & SignInManager

I am trying to figure out how to inject UserManager and SignInManager.我想弄清楚如何注入 UserManager 和 SignInManager。 I have installed Ninject in my application and I am using it in the following manner:我已经在我的应用程序中安装了 Ninject,并以下列方式使用它:

Please consider this to be a brand new project.请认为这是一个全新的项目。 Inside Startup.cs I have the following:在 Startup.cs 中,我有以下内容:

public partial class Startup
{
    public void Configuration(IAppBuilder app)
    {
        ConfigureAuth(app);

        app.UseNinjectMiddleware(CreateKernel);
    }

    private static IKernel CreateKernel()
    {
        var kernel = new StandardKernel();
        kernel.Load(Assembly.GetExecutingAssembly());


        return kernel;
    }
}

now if I were to create some Dummy class and try to inject it based on its interface that works.现在,如果我要创建一些 Dummy 类并尝试根据其有效的接口注入它。 I have tested it.我已经测试过了。 What I am trying to figure out is how would I now strip out the following out of Startup.Auth.cs and inject it.我想弄清楚的是我现在如何从 Startup.Auth.cs 中删除以下内容并注入它。 Having no interfaces I can rely on, I am not sure how this is done:没有我可以依赖的接口,我不确定这是如何完成的:

app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);

Just to clarify one more time, my question is: How do I instantiate ApplicationUserManager and ApplicationSignInManager and inject it in my controller parameters.再澄清一次,我的问题是:如何实例化 ApplicationUserManager 和 ApplicationSignInManager 并将其注入我的控制器参数中。 Here is the controller that I am trying to inject this into:这是我试图将其注入的控制器:

public AccountController(ApplicationUserManager userManager, ApplicationSignInManager signInManager)
{
    UserManager = userManager;
    SignInManager = signInManager;
}

EDIT:编辑:

Here is what I tried:这是我尝试过的:

private static IKernel CreateKernel()
{
    var kernel = new StandardKernel();
    kernel.Load(Assembly.GetExecutingAssembly());

    kernel.Bind<IUserStore<ApplicationUser>>().To<UserStore<ApplicationUser>>();
    kernel.Bind<UserManager<ApplicationUser>>().ToSelf();

    return kernel;
}

But with this I get null reference error但是有了这个,我得到了空引用错误

Prerequisites先决条件

Start a new MVC5 application using the MVC template.使用 MVC 模板启动一个新的 MVC5 应用程序。 This will install all the necessary dependencies as well as deploy the Startup.Auth.cs file which contains the bootstrap code for Microsoft.AspNet.Identity (it als includes the all the references for Microsoft.AspNet.Identity).这将安装所有必要的依赖项并部署Startup.Auth.cs文件,该文件包含Microsoft.AspNet.Identity的引导程序代码(它还包括Microsoft.AspNet.Identity的所有引用)。

Install the following packages and update them to the latest afterwards.安装以下软件包,然后将它们更新到最新版本。

Install-Package Ninject
Install-Package Ninject.MVC5

Configuration配置

Remove the default constructor on the AccountController so only the parameterized constructor remains.删除AccountController上的默认构造函数,以便只保留参数化构造函数。 It should have the follownig signature.它应该具有以下签名。

public AccountController(ApplicationUserManager userManager, ApplicationSignInManager signInManager)

This will ensure that you will get an error if injection fails which is what we want.这将确保如果注入失败,您将收到错误消息,这正是我们想要的。

NInject Configuration NInject 配置

The NInject NuGet package deployment will have created a file named NinjectWebCommon.cs where the boiler plate NInject registration takes place. NInject NuGet 包部署将创建一个名为NinjectWebCommon.cs的文件,在其中进行样板 NInject 注册。 This has a method with the following signature which you can extend with your registrations.这有一个带有以下签名的方法,您可以使用您的注册进行扩展。

private static void RegisterServices(IKernel kernel)

Now we will add the following code to this method to get NInject automatically inject the ApplicationSignInManager and ApplicationUserManager instances.现在我们将在此方法中添加以下代码,以使 NInject 自动注入ApplicationSignInManagerApplicationUserManager实例。

private static void RegisterServices(IKernel kernel) {
    kernel.Bind<IUserStore<ApplicationUser>>().To<UserStore<ApplicationUser>>();
    kernel.Bind<UserManager<ApplicationUser>>().ToSelf();

    kernel.Bind<HttpContextBase>().ToMethod(ctx => new HttpContextWrapper(HttpContext.Current)).InTransientScope();

    kernel.Bind<ApplicationSignInManager>().ToMethod((context)=>
    {
        var cbase = new HttpContextWrapper(HttpContext.Current);
        return cbase.GetOwinContext().Get<ApplicationSignInManager>();
    });

    kernel.Bind<ApplicationUserManager>().ToSelf();
}

Thats it.就是这样。 Now you should be able to navigate to the Login or Register links and injection will occur.现在您应该能够导航到登录或注册链接,并且会发生注入。

Alternate Approach替代方法

I prefer a Proxy approach that exposes limited functionality for the ApplicationSignInManager and the ApplicationUserManager instances.我更喜欢为ApplicationSignInManagerApplicationUserManager实例公开有限功能的代理方法。 I then inject this proxy into the necessary controllers.然后我将此代理注入到必要的控制器中。 It helps abstract some of the Identity information away from the controllers which makes it easier to change in the future.它有助于从控制器中提取一些身份信息,这使得将来更容易更改。 This is not a new concept by any means and whether you do this or not depends on the size and complexity of your project as well as how you want to handle dependencies.这绝不是一个新概念,您是否这样做取决于项目的大小和复杂性以及您希望如何处理依赖项。 So the benefits are (common actually for any proxy):所以好处是(实际上对于任何代理都很常见):

  • You can abstract some of the dependencies away from your code您可以从代码中抽象出一些依赖项
  • You can streamline some of the calls within the api可以精简api内的一些调用
  • You can expose only that functionality that you want to use including configurable parts您只能公开您想要使用的功能,包括可配置的部分
  • Change management should be easier if the interfaces ever change, now you change the calls in your proxy instead of all the calling code across your controllers.如果接口发生变化,变更管理应该更容易,现在您更改代理中的调用而不是控制器中的所有调用代码。

Code example:代码示例:

public interface IAuthManager
{
    Task<SignInStatus> PasswordSignInAsync(string userName, string password, bool rememberMe);
}

public class AuthManager : IAuthManager
{
    private ApplicationUserManager _userManager;
    ApplicationSignInManager _signInManager;

    public AuthManager(ApplicationUserManager userManager, ApplicationSignInManager signInManager)
    {
        this._userManager = userManager;
        this._signInManager = signInManager;
    }

    public Task<SignInStatus> PasswordSignInAsync(string userName, string password, bool rememberMe)
    {
        return _signInManager.PasswordSignInAsync(userName, password, rememberMe, true);
    }
}

Add the following line in your NInject dependency registration.在您的 NInject 依赖项注册中添加以下行。

kernel.Bind<IAuthManager>().To<AuthManager>();

Alter your AccountController constructor to take in an instance of IAuthManager .更改您的AccountController构造函数以接收IAuthManager的实例。 Finally change your methods to refer to this proxy instead of the ASP.NET Identity classes directly.最后更改您的方法以引用此代理,而不是直接引用 ASP.NET Identity 类。

Disclaimer - I did not wire up a complex call, just a very simple one to illustrate my point.免责声明 - 我没有接到一个复杂的电话,只是一个非常简单的电话来说明我的观点。 This is also entirely optional and whether you do it or not really should depend on the scope and size of your project and how you plan on using the ASP.NET Identity framework这也是完全可选的,您是否真的这样做应该取决于项目的范围和大小以及您计划如何使用 ASP.NET Identity 框架

To give an exact answer to what my question stated, here is the code and instructions:为了准确回答我的问题,这里是代码和说明:

Step 1: Create custom User Store第 1 步:创建自定义用户存储

public class ApplicationUserStore : UserStore<ApplicationUser>
{
    public ApplicationUserStore(ApplicationDbContext context)
        : base(context)
    {
    }
}

Step 2: Update ApplicationUserManager and move code from Create method into constructor第 2 步:更新 ApplicationUserManager 并将代码从 Create 方法移动到构造函数中

public class ApplicationUserManager : UserManager<ApplicationUser>
{
    public ApplicationUserManager(IUserStore<ApplicationUser> store, IdentityFactoryOptions<ApplicationUserManager> options)
        : base(store)
    {
        this.UserValidator = new UserValidator<ApplicationUser>(this)
        {
            AllowOnlyAlphanumericUserNames = false,
            RequireUniqueEmail = true
        };

        // Configure validation logic for passwords
        this.PasswordValidator = new PasswordValidator
        {
            RequiredLength = 6,
            RequireNonLetterOrDigit = true,
            RequireDigit = true,
            RequireLowercase = true,
            RequireUppercase = true,
        };

        // Configure user lockout defaults
        this.UserLockoutEnabledByDefault = true;
        this.DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5);
        this.MaxFailedAccessAttemptsBeforeLockout = 5;

        // Register two-factor authentication providers. This application uses Phone and Emails as a step of receiving a code for verifying the user
        // You can write your own provider and plug it in here.
        this.RegisterTwoFactorProvider("Phone Code", new PhoneNumberTokenProvider<ApplicationUser>
        {
            MessageFormat = "Your security code is {0}"
        });
        this.RegisterTwoFactorProvider("Email Code", new EmailTokenProvider<ApplicationUser>
        {
            Subject = "Security Code",
            BodyFormat = "Your security code is {0}"
        });
        this.EmailService = new EmailService();
        this.SmsService = new SmsService();
        var dataProtectionProvider = options.DataProtectionProvider;
        if (dataProtectionProvider != null)
        {
            this.UserTokenProvider =
                new DataProtectorTokenProvider<ApplicationUser>(dataProtectionProvider.Create("ASP.NET Identity"));
        }
    }
}

Step 3: Modify the Startup.Auth class and comment out the following code第三步:修改Startup.Auth类,注释掉以下代码

//app.CreatePerOwinContext(ApplicationDbContext.Create);
//app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
//app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);

Step 4: Update Account Controller (or any other controller in question) and add the following constructor第 4 步:更新帐户控制器(或任何其他有问题的控制器)并添加以下构造函数

public AccountController(ApplicationUserManager userManager, ApplicationSignInManager signInManager, IAuthenticationManager authManager)
{
    _userManager = userManager;
    _signInManager = signInManager;
    _authManager = authManager;
}

Step 5: Update Account Controller and make properties only retrivable as so:第 5 步:更新帐户控制器并使属性仅可检索,如下所示:

public ApplicationSignInManager SignInManager
{
    get
    {
        return _signInManager;
    }
}

public ApplicationUserManager UserManager
{
    get
    {
        return _userManager;
    }
}

private IAuthenticationManager AuthenticationManager
{
    get
    {
        return _authManager;
    }
}

Step 6: Update Startup.cs第 6 步:更新 Startup.cs

public partial class Startup
{
    private IAppBuilder _app;
    public void Configuration(IAppBuilder app)
    {
        ConfigureAuth(app);
        _app = app;
        app.UseNinjectMiddleware(CreateKernel);
    }

    private IKernel CreateKernel()
    {
        var kernel = new StandardKernel();
        kernel.Load(Assembly.GetExecutingAssembly());

        kernel.Bind<ApplicationDbContext>().ToSelf().InRequestScope();
        kernel.Bind<IUserStore<ApplicationUser>>().To<ApplicationUserStore>();
        kernel.Bind<ApplicationUserManager>().ToSelf();
        kernel.Bind<ApplicationSignInManager>().ToSelf();
        kernel.Bind<IAuthenticationManager>().ToMethod(x => HttpContext.Current.GetOwinContext().Authentication);
        kernel.Bind<IDataProtectionProvider>().ToMethod(x => _app.GetDataProtectionProvider());

        return kernel;
    }
}

To further expand the answer to this question, based on the comments I have received:根据我收到的评论,进一步扩大对这个问题的回答:

These managers should not be injected as classes as then you are not accomplishing DI.这些管理器不应该作为类注入,因为那样你就没有完成 DI。 What should be done instead is create multiple interfaces that further separate and group methods of UserManager according to your needs.应该做的是创建多个接口,根据您的需要进一步分离和分组 UserManager 的方法。 Here is an example:下面是一个例子:

public interface IUserManagerSegment
{
    Task<IdentityResult> CreateAsync(ApplicationUser user, string password);
    Task<IdentityResult> CreateAsync(ApplicationUser user);
    Task<IdentityResult> ConfirmEmailAsync(string userId, string token);
    Task<ApplicationUser> FindByNameAsync(string userName);
    Task<bool> IsEmailConfirmedAsync(string userId);
    Task<IdentityResult> ResetPasswordAsync(string userId, string token, string newPassword);
    Task<IList<string>> GetValidTwoFactorProvidersAsync(string userId);
    Task<IdentityResult> AddLoginAsync(string userId, UserLoginInfo login);
    void Dispose(bool disposing);
    void Dispose();
}

The above method has a list of few random methods I chose just to illustrate the point.上面的方法列出了我选择的一些随机方法,只是为了说明这一点。 With this said, we would now inject the method based on the interface such as this:话虽如此,我们现在将基于接口注入方法,例如:

kernel.Bind<IUserManagerSegment>().To<ApplicationUserManager>();

And now our AccountController constructor would look like this:现在我们的 AccountController 构造函数看起来像这样:

public AccountController(IUserManagerSegment userManager, ApplicationSignInManager signInManager, IAuthenticationManager authManager)  
{
    _userManager = userManager;
    _signInManager = signInManager;
    _authManager = authManager;
}

Same thing should be done to SignInManager and AuthenticationManager.应该对 SignInManager 和 AuthenticationManager 做同样的事情。

The code above has been tested and is working.上面的代码已经过测试并且可以正常工作。 Just ensure you have referenced the following DLLs:只需确保您已引用以下 DLL:

Ninject.dll注入文件
Ninject.Web.Common Ninject.Web.Common
Ninject.Web.Common.OwinHost Ninject.Web.Common.OwinHost
Ninject.Web.Mvc Ninject.Web.Mvc

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何依赖注入SignInManager? - How do I dependency inject SignInManager? 外部 UserManager 和内存中 SignInManager - External UserManager and in-memory SignInManager UserManager.CheckPasswordAsync vs SignInManager.PasswordSignInAsync - UserManager.CheckPasswordAsync vs SignInManager.PasswordSignInAsync 使用ServiceProvider将IServiceProvider注入SignInManager - Inject IServiceProvider using ServiceProvider into SignInManager 如何将 UserManager 注入 Program.cs 或 Startup.cs - How to inject UserManager to Program.cs or Startup.cs 如何对需要 UserManager 的 ASP .NET Core 3.0+ Razor 页面处理程序进行单元测试<tuser>和登录管理器<tuser> ?</tuser></tuser> - How do I unit test ASP .NET Core 3.0+ Razor Page handlers that require UserManager<TUser> and SignInManager<TUser>? 如何将UserManager注入到ASP.NET Core 2.0中的另一个服务 - How to inject UserManager to another service in ASP.NET Core 2.0 无法在 Abp 控制器中注入 UserManager 依赖项 - Can't inject UserManager dependency in Abp controller SignInManager,它是什么以及如何使用,何时使用? - SignInManager,what it is and how,when to use? 在 ASP.NET 核心应用程序中使用 UserManager 和 SignInManager 创建注册表时出错 - Error while creating a Register Form using UserManager and SignInManager in an ASP.NET core application
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM