如何为ASP.NET 5 MVC 6实现NoSQL身份提供程序

时间:2022-11-21 03:29:35

There is no documentation at all.

根本没有文档。

I know I have to implement my own IUser, my own IUserSTore and somehow register them in the startup.cs. I removed all references to EntityFramework as I want to use a NoSQL backend.

我知道我必须实现自己的IUser,我自己的IUserSTore并以某种方式在startup.cs中注册它们。我删除了对EntityFramework的所有引用,因为我想使用NoSQL后端。

The "convention" philosophy is very nice as long as it is documented and public.

只要记录和公开,“惯例”理念就非常好。

Any hint?

1 个解决方案

#1


8  

I just did a custom implementation of Identity 2.0, and as you said, I didn't find any useful documentation. But fortunately I managed to achieve my goal.

我刚刚做了Identity 2.0的自定义实现,正如你所说,我没有找到任何有用的文档。但幸运的是,我设法实现了我的目标。

I'll answer your question assuming that you are using a N layered architecture, isolating your views from your business logic and your business logic from your data access layer. And assuming as well there's a dependency injection container being used such as Unity.

假设您使用的是N层次结构,将您的视图与业务逻辑和业务逻辑从数据访问层隔离开来,我将回答您的问题。并假设还有一个依赖注入容器,如Unity。

I'll explain the steps you must follow to use the Identity framework with a custom data access:

我将解释在使用Identity框架和自定义数据访问时必须遵循的步骤:

First you have to declare your domain class, implementing IUser and, if you want, adding custom properties to it:

首先,您必须声明您的域类,实现IUser,如果需要,还可以向其添加自定义属性:

//This class is implementing IUser with Guid as type because
//I needed to use Guid as default Id.
public class CustomUser : IUser<Guid>
{
      public string CustomProperty { get; set; }
}

Then, in your business logic layer, you should have a class that handles all tasks related to the user authorization, login, password recovery, among others. This class must inherit from UserManager. The result would be something as follows:

然后,在业务逻辑层中,您应该有一个类来处理与用户授权,登录,密码恢复等相关的所有任务。该类必须从UserManager继承。结果如下:

// Business layer class must inherit from UserManager with
// CustomUser and Guid as types
public AuthorizationManager : UserManager<CustomUser, Guid>, IAuthorizationManager
{
      private readonly ICustomUserMongoRepository repository;
      private readonly ICustomEmailService emailService;
      private readonly ICustomTokenProvider tokenProvider;

      // Parameters being injected by Unity.
      // container.RegisterType<ICustomUserMongoRepository, CustomUserMongoRepository>();
      // ..
      // ..
      public AuthorizationManager(
                   ICustomUserMongoRepository repository,
                   ICustomEmailService emailService,
                   ICustomTokenProvider tokenProvider
                   ) 
                                 // calling base constructor passing
                                 // a repository which implements
                                 // IUserStore, among others.
                                 : base(repository)
      {
            this.repository = repository;

            // this.EmailService is a property of UserManager and
            // it has to be set to send emails by your class
            this.EmailService = emailService;

            // this.UserTokenProvider is a property of UserManager and
            // it has to be set to generate tokens for user password
            // recovery and confirmation tokens
            this.UserTokenProvider = tokenProvider;
      }
}

When inheriting from UserManager, it will provide a series of methods used by Identity and it will force your class to call the base constructor passing a repository, but not any repository, it's mandatory for the repository to implement the interfaces: IUserStore, IPasswordStore, depending on your requirements.

从UserManager继承时,它将提供Identity使用的一系列方法,它将强制您的类调用基础构造函数来传递存储库,而不是任何存储库,存储库必须实现接口:IUserStore,IPasswordStore,取决于根据您的要求。

Here is when cool stuff happens. In your data access layer you must have your custom implementation of repository pattern connecting to a NoSQL database (let's assume it's Mongo). So, your ICustomUserMongoRepository should look something like this:

这是很酷的事情发生的时候。在您的数据访问层中,您必须将存储库模式的自定义实现连接到NoSQL数据库(假设它是Mongo)。因此,您的ICustomUserMongoRepository应如下所示:

public interface ICustomUserMongoRepository : IUserPasswordStore<CustomUser, Guid>, IUserEmailStore<CustomUser, Guid>, IUserRoleStore<CustomUser, Guid>
{
}

And your Mongo repository should be something like this

而你的Mongo存储库应该是这样的

public CustomUserMongoRepository : MongoRepository<CustomUser>, ICustomUserMongoRepository
{
      // Here you must have your custom implementation (using Mongo) of 
      // ICustomUserRepository which is requesting your class to 
      // implement IUserPasswordStore methods as well

      public Task CreateAsync(CustomUser user)
      {
            //Custom Mongo implementation
      }

      public Task DeleteAsync(CustomUser user)
      {
            //Custom Mongo implementation
      }

      public Task GetEmailAsync(CustomUser user)
      {
            //Custom Mongo implementation
      }

      public Task GetEmailConfirmedAsync(CustomUser user)
      {
            //Custom Mongo implementation
      }

      // ...
}

Then finally your controller would look something like this:

最后你的控制器看起来像这样:

public class AuthController : Controller
{

    private readonly IAuthorizationManager manager;        

      // Manager being injected by Unity.
      // container.RegisterType<IAuthorizationManager, AuthorizationManager>();
    public AuthController(IAuthorizationManager manager)
    {
          this.manager = manager;
    }

    // Receives a LogInViewModel with all data needed to allow users to log in
    [HttpPost]
    public async Task<ActionResult> LogIn(LogInViewModel viewModel)
    {
         // FindAsync it's a method inherited from UserManager, that's
         // using the Mongo repository passed to the base class 
         // in the AuthorizationManager constructor
         var user = this.manager.FindAsync(viewModel.Email, viewModel.Password);

         if(user != null){ // Log in user and create user session }
         else { // Wrong username or password }

    }
}

IMPORTANT!

The interface IAuthorizationManager it's used to deliver quality software, based on SOLID principles. And if you look closer and put a deep thought into it, you'll notice that this interface must have all UserManager's methods to allow the AuthController to call all of the inherited methods by the AuthorizationManager from the UserManager class

接口IAuthorizationManager它用于提供基于SOLID原则的高质量软件。如果你仔细观察并深入思考它,你会注意到这个接口必须拥有所有UserManager的方法,允许AuthController通过UserManager类中的AuthorizationManager调用所有继承的方法。

Sorry for the long post. It's pretty hard to explain this whole process in few lines. I hope it helps. If you have any doubts or questions, comment this answer and I'll reply back as soon as possible.

对不起,很长的帖子。很难用几行来解释整个过程。我希望它有所帮助。如果您有任何疑问或疑问,请回答此问题,我会尽快回复。

#1


8  

I just did a custom implementation of Identity 2.0, and as you said, I didn't find any useful documentation. But fortunately I managed to achieve my goal.

我刚刚做了Identity 2.0的自定义实现,正如你所说,我没有找到任何有用的文档。但幸运的是,我设法实现了我的目标。

I'll answer your question assuming that you are using a N layered architecture, isolating your views from your business logic and your business logic from your data access layer. And assuming as well there's a dependency injection container being used such as Unity.

假设您使用的是N层次结构,将您的视图与业务逻辑和业务逻辑从数据访问层隔离开来,我将回答您的问题。并假设还有一个依赖注入容器,如Unity。

I'll explain the steps you must follow to use the Identity framework with a custom data access:

我将解释在使用Identity框架和自定义数据访问时必须遵循的步骤:

First you have to declare your domain class, implementing IUser and, if you want, adding custom properties to it:

首先,您必须声明您的域类,实现IUser,如果需要,还可以向其添加自定义属性:

//This class is implementing IUser with Guid as type because
//I needed to use Guid as default Id.
public class CustomUser : IUser<Guid>
{
      public string CustomProperty { get; set; }
}

Then, in your business logic layer, you should have a class that handles all tasks related to the user authorization, login, password recovery, among others. This class must inherit from UserManager. The result would be something as follows:

然后,在业务逻辑层中,您应该有一个类来处理与用户授权,登录,密码恢复等相关的所有任务。该类必须从UserManager继承。结果如下:

// Business layer class must inherit from UserManager with
// CustomUser and Guid as types
public AuthorizationManager : UserManager<CustomUser, Guid>, IAuthorizationManager
{
      private readonly ICustomUserMongoRepository repository;
      private readonly ICustomEmailService emailService;
      private readonly ICustomTokenProvider tokenProvider;

      // Parameters being injected by Unity.
      // container.RegisterType<ICustomUserMongoRepository, CustomUserMongoRepository>();
      // ..
      // ..
      public AuthorizationManager(
                   ICustomUserMongoRepository repository,
                   ICustomEmailService emailService,
                   ICustomTokenProvider tokenProvider
                   ) 
                                 // calling base constructor passing
                                 // a repository which implements
                                 // IUserStore, among others.
                                 : base(repository)
      {
            this.repository = repository;

            // this.EmailService is a property of UserManager and
            // it has to be set to send emails by your class
            this.EmailService = emailService;

            // this.UserTokenProvider is a property of UserManager and
            // it has to be set to generate tokens for user password
            // recovery and confirmation tokens
            this.UserTokenProvider = tokenProvider;
      }
}

When inheriting from UserManager, it will provide a series of methods used by Identity and it will force your class to call the base constructor passing a repository, but not any repository, it's mandatory for the repository to implement the interfaces: IUserStore, IPasswordStore, depending on your requirements.

从UserManager继承时,它将提供Identity使用的一系列方法,它将强制您的类调用基础构造函数来传递存储库,而不是任何存储库,存储库必须实现接口:IUserStore,IPasswordStore,取决于根据您的要求。

Here is when cool stuff happens. In your data access layer you must have your custom implementation of repository pattern connecting to a NoSQL database (let's assume it's Mongo). So, your ICustomUserMongoRepository should look something like this:

这是很酷的事情发生的时候。在您的数据访问层中,您必须将存储库模式的自定义实现连接到NoSQL数据库(假设它是Mongo)。因此,您的ICustomUserMongoRepository应如下所示:

public interface ICustomUserMongoRepository : IUserPasswordStore<CustomUser, Guid>, IUserEmailStore<CustomUser, Guid>, IUserRoleStore<CustomUser, Guid>
{
}

And your Mongo repository should be something like this

而你的Mongo存储库应该是这样的

public CustomUserMongoRepository : MongoRepository<CustomUser>, ICustomUserMongoRepository
{
      // Here you must have your custom implementation (using Mongo) of 
      // ICustomUserRepository which is requesting your class to 
      // implement IUserPasswordStore methods as well

      public Task CreateAsync(CustomUser user)
      {
            //Custom Mongo implementation
      }

      public Task DeleteAsync(CustomUser user)
      {
            //Custom Mongo implementation
      }

      public Task GetEmailAsync(CustomUser user)
      {
            //Custom Mongo implementation
      }

      public Task GetEmailConfirmedAsync(CustomUser user)
      {
            //Custom Mongo implementation
      }

      // ...
}

Then finally your controller would look something like this:

最后你的控制器看起来像这样:

public class AuthController : Controller
{

    private readonly IAuthorizationManager manager;        

      // Manager being injected by Unity.
      // container.RegisterType<IAuthorizationManager, AuthorizationManager>();
    public AuthController(IAuthorizationManager manager)
    {
          this.manager = manager;
    }

    // Receives a LogInViewModel with all data needed to allow users to log in
    [HttpPost]
    public async Task<ActionResult> LogIn(LogInViewModel viewModel)
    {
         // FindAsync it's a method inherited from UserManager, that's
         // using the Mongo repository passed to the base class 
         // in the AuthorizationManager constructor
         var user = this.manager.FindAsync(viewModel.Email, viewModel.Password);

         if(user != null){ // Log in user and create user session }
         else { // Wrong username or password }

    }
}

IMPORTANT!

The interface IAuthorizationManager it's used to deliver quality software, based on SOLID principles. And if you look closer and put a deep thought into it, you'll notice that this interface must have all UserManager's methods to allow the AuthController to call all of the inherited methods by the AuthorizationManager from the UserManager class

接口IAuthorizationManager它用于提供基于SOLID原则的高质量软件。如果你仔细观察并深入思考它,你会注意到这个接口必须拥有所有UserManager的方法,允许AuthController通过UserManager类中的AuthorizationManager调用所有继承的方法。

Sorry for the long post. It's pretty hard to explain this whole process in few lines. I hope it helps. If you have any doubts or questions, comment this answer and I'll reply back as soon as possible.

对不起,很长的帖子。很难用几行来解释整个过程。我希望它有所帮助。如果您有任何疑问或疑问,请回答此问题,我会尽快回复。