Skip to content
.NET 开发者指北.NET 开发者指北
CMS
.NET指北
FreeKit
Docker
关于
博客
github icon
    • FreeKit 指北
      • FreeKit 基础包
        • FreeKit Extras 扩展包
          • AspNetCore Identity FreeSql的实现
            • IGeekFan.AspNetCore.Identity.FreeSql
              • 扩展用户、角色
                • 配置用户、角色的FulentAPI
                  • 配置 Identity+FreeSql
                    • 软删除
                  • Email 邮件
                    • Modularity 模块化
                      • Localization 本地化

                      AspNetCore Identity FreeSql的实现

                      calendar icon2022年6月2日timer icon大约 3 分钟word icon约 1001 字

                      此页内容
                      • IGeekFan.AspNetCore.Identity.FreeSql
                        • 扩展用户、角色
                        • 配置用户、角色的FulentAPI
                        • 配置 Identity+FreeSql
                        • 软删除

                      # AspNetCore Identity FreeSql的实现

                      # IGeekFan.AspNetCore.Identity.FreeSql

                      是asp.net core 6 的identity的freesql存储的实现

                      • 支持.NET 6.0
                      • 安装包
                      dotnet add package IGeekFan.AspNetCore.Identity.FreeSql
                      
                      1
                      • 新增 FreeSql的Provider 相关包
                      dotnet add package FreeSql.Provider.MySqlConnector
                      
                      1

                      # 扩展用户、角色

                      public class AppUser : IdentityUser<Guid>
                      {
                          public string FirstName { get; set; }
                          public string LastName { get; set; }
                      }
                      public class AppRole : IdentityRole<Guid>
                      {
                      
                      }
                      public class AppIdentityDbContext : IdentityDbContext<AppUser, AppRole, Guid>
                      {
                          public AppIdentityDbContext(IOptions<IdentityOptions> identityOptions, IFreeSql fsql, DbContextOptions options)
                          : base(identityOptions.Value, fsql, options)
                          {
                          }
                      
                          protected override void OnConfiguring(DbContextOptionsBuilder builder)
                          {
                              //这里直接指定一个静态的 IFreeSql 对象即可,切勿重新 Build()
                          }
                      
                          protected override void OnModelCreating(ICodeFirst codefirst)
                          {
                              base.OnModelCreating(codefirst);
                              //批量
                              //codefirst.ApplyConfigurationsFromAssembly(typeof(AppUserConfiguration).Assembly);
                              codefirst.ApplyConfiguration(new AppUserConfiguration());
                              codefirst.ApplyConfiguration(new AppRoleConfiguration());
                          }
                      }
                      
                      
                      1
                      2
                      3
                      4
                      5
                      6
                      7
                      8
                      9
                      10
                      11
                      12
                      13
                      14
                      15
                      16
                      17
                      18
                      19
                      20
                      21
                      22
                      23
                      24
                      25
                      26
                      27
                      28
                      29
                      30
                      31

                      # 配置用户、角色的FulentAPI

                      public class AppUserConfiguration : IEntityTypeConfiguration<AppUser>
                      {
                          public void Configure(EfCoreTableFluent<AppUser> builder)
                          {
                              builder.Property(x => x.FirstName).HasMaxLength(50);
                              builder.Property(x => x.LastName).HasMaxLength(50);
                          }
                      }
                      public class AppRoleConfiguration : IEntityTypeConfiguration<AppRole>
                      {
                          public void Configure(EfCoreTableFluent<AppRole> builder)
                          {
                          }
                      }
                      
                      1
                      2
                      3
                      4
                      5
                      6
                      7
                      8
                      9
                      10
                      11
                      12
                      13
                      14
                      • appsettings.json 该配置通过方法UseConnectionString读取如下配置
                      "ConnectionStrings": {
                          "MySql": "Data Source=localhost;Port=3306;User ID=root;Password=root;Initial Catalog=aspnetcoreidentity;Charset=utf8mb4;SslMode=none;Max pool size=1;Connection LifeTime=20"
                      }
                      
                      1
                      2
                      3

                      # 配置 Identity+FreeSql

                      • 新增一个扩展方法,引用 aspnetcore identity 相关服务
                      public static IServiceCollection AddFreeSqlIdentity(this IServiceCollection services, IConfiguration configuration)
                      {
                          Func<IServiceProvider, IFreeSql> fsql = r =>
                          {
                              IFreeSql fsql = new FreeSqlBuilder()
                                      .UseConnectionString(DataType.MySql, configuration["ConnectionStrings:MySql"])
                                     //.UseNameConvert(NameConvertType.PascalCaseToUnderscoreWithLower)
                                      .UseAutoSyncStructure(true) //自动同步实体结构到数据库,FreeSql不会扫描程序集,只有CRUD时才会生成表。
                                      .UseMappingPriority(MappingPriorityType.FluentApi, MappingPriorityType.Attribute, MappingPriorityType.Aop)
                                      .UseMonitorCommand(cmd =>
                                      {
                                          Trace.WriteLine(cmd.CommandText + ";");
                                      })
                                      .Build();
                              //软删除
                              fsql.GlobalFilter.Apply<ISoftDelete>("IsDeleted", a => a.IsDeleted == false);      
                              return fsql;
                          };
                      
                          services.AddSingleton<IFreeSql>(fsql);
                          services.AddFreeRepository();
                          services.AddScoped<UnitOfWorkManager>();
                      
                          using (var scope = services.BuildServiceProvider().CreateScope())
                          {
                              var orm = scope.ServiceProvider.GetRequiredService<IFreeSql>();
                      
                              //只有实例化了AppIdentityDbContext,才能正常调用OnModelCreating,不然直接使用仓储,无法调用DbContext中的OnModelCreating方法,配置的TodoConfiguration 就会没有生效
                              services.AddFreeDbContext<AppIdentityDbContext>(options => options
                                          .UseFreeSql(orm)
                                          .UseOptions(new DbContextOptions()
                                          {
                                              EnableCascadeSave = true
                                          }));
                          }
                      
                          services.AddAuthentication(o =>
                          {
                              o.DefaultScheme = IdentityConstants.ApplicationScheme;
                              o.DefaultSignInScheme = IdentityConstants.ExternalScheme;
                          })
                          .AddIdentityCookies(o => { });
                          
                          services.AddIdentityCore<AppUser>(o =>
                                  {
                                      o.SignIn.RequireConfirmedEmail = false;
                                      o.Stores.MaxLengthForKeys = 128;
                                  })
                                  .AddRoles<AppRole>()
                                  .AddSignInManager()
                                  .AddFreeSqlStores<AppIdentityDbContext>()
                                  .AddDefaultTokenProviders();;
                      
                          // 如果是MVC 另外安装包 <PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="6.0.7" /> 使用AddDefaultIdentity方法
                          // services.AddDefaultIdentity<AppUser>(options => options.SignIn.RequireConfirmedAccount = true).AddRoles<AppRole>()
                          //        .AddFreeSqlStores<AppIdentityDbContext>().AddDefaultTokenProviders();
                      
                          return services;
                      }
                      
                      1
                      2
                      3
                      4
                      5
                      6
                      7
                      8
                      9
                      10
                      11
                      12
                      13
                      14
                      15
                      16
                      17
                      18
                      19
                      20
                      21
                      22
                      23
                      24
                      25
                      26
                      27
                      28
                      29
                      30
                      31
                      32
                      33
                      34
                      35
                      36
                      37
                      38
                      39
                      40
                      41
                      42
                      43
                      44
                      45
                      46
                      47
                      48
                      49
                      50
                      51
                      52
                      53
                      54
                      55
                      56
                      57
                      58
                      59

                      # 软删除

                      public interface ISoftDelete
                      {
                          bool IsDeleted { get; set; }
                      }
                      
                      1
                      2
                      3
                      4

                      因为FreeSql只有运行时才会生成表,我们增加定义一个扩展方法

                      /// <summary>
                      /// 自定义Scope 的Serivce 执行 DbContext中的OnModelCreating
                      /// </summary>
                      /// <param name="serviceProvider"></param>
                      /// <returns></returns>
                      
                      public static IServiceProvider RunScopeService(this IServiceProvider serviceProvider)
                      {
                          //在项目启动时,从容器中获取IFreeSql实例,并执行一些操作:同步表,种子数据,FluentAPI等
                          using (IServiceScope serviceScope = serviceProvider.CreateScope())
                          {
                              var freeSql = serviceScope.ServiceProvider.GetRequiredService<IFreeSql>();
                              using var dbContext = serviceScope.ServiceProvider.GetRequiredService<AppIdentityDbContext>();
                      
                              freeSql.CodeFirst.SyncStructure(
                                  typeof(AppUser),
                                  typeof(AppRole),
                                  typeof(IdentityUserLogin<Guid>),
                                  typeof(IdentityUserRole<Guid>),
                                  typeof(IdentityUserClaim<Guid>),
                                  typeof(IdentityRoleClaim<Guid>),
                                  typeof(IdentityUserToken<Guid>)
                                  );
                          }
                          return serviceProvider;
                      }
                      
                      1
                      2
                      3
                      4
                      5
                      6
                      7
                      8
                      9
                      10
                      11
                      12
                      13
                      14
                      15
                      16
                      17
                      18
                      19
                      20
                      21
                      22
                      23
                      24
                      25
                      26

                      在Program中Build后,我们执行此方法,以保证DbContext中的OnModelCreating生效

                      WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
                      builder.Services.AddFreeSqlIdentity(builder.Configuration);
                      
                      WebApplication app = builder.Build();
                      //自定义Scope 的Serivce 执行 DbContext中的OnModelCreating
                      app.Services.RunScopeService();
                      
                      
                      1
                      2
                      3
                      4
                      5
                      6
                      7
                      [ApiController]
                      [Route("api/[controller]")]
                      public class AppUserController : ControllerBase
                      {
                          private readonly ILogger<AppUserController> _logger;
                          private readonly UserManager<AppUser> _userManager;
                          private readonly IUserStore<AppUser> _userStore;
                          private readonly IUserEmailStore<AppUser> _emailStore;
                          private readonly SignInManager<AppUser> _signInManager;
                          public AppUserController(ILogger<AppUserController> logger, UserManager<AppUser> userManager, SignInManager<AppUser> signInManager, IUserStore<AppUser> userStore)
                          {
                              _logger = logger;
                              _userManager = userManager;
                              _signInManager = signInManager;
                              _userStore = userStore;
                              _emailStore = GetEmailStore();
                          }
                          private IUserEmailStore<AppUser> GetEmailStore()
                          {
                              if (!_userManager.SupportsUserEmail)
                              {
                                  throw new NotSupportedException("The default UI requires a user store with email support.");
                              }
                              return (IUserEmailStore<AppUser>)_userStore;
                          }
                          /// <summary>
                          /// 创建用户示例
                          /// </summary>
                          /// <param name="createAppUser"></param>
                          /// <returns></returns>
                          /// <exception cref="ArgumentException"></exception>
                          [HttpPost]
                          public async Task<IResult> CreateUserAsync([FromBody] CreateAppUser createAppUser)
                          {
                              AppUser user = new AppUser()
                              {
                                  FirstName = createAppUser.FirstName,
                                  LastName = createAppUser.LastName,
                                  EmailConfirmed = true //直接让邮件激活
                              };
                              await _userStore.SetUserNameAsync(user, createAppUser.Email, CancellationToken.None);
                              await _emailStore.SetEmailAsync(user, createAppUser.Email, CancellationToken.None);
                              var identityResult = await _userManager.CreateAsync(user, createAppUser.Password);
                      
                              if (identityResult.Succeeded)
                              {
                                  _logger.LogInformation("User created a new account with password.");
                                  //获取userid
                                  var userId = await _userManager.GetUserIdAsync(user);
                                  //生成邮件激活码
                                  var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
                                  code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
                                  return Results.Ok("Register Success");
                                  //如果邮件 EmailConfirmed 为false时,通过此方式发送激活邮件
                                  //await _emailSender.SendEmailAsync(Input.Email, "Confirm your email",
                                  //    $"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");
                              }
                              if (identityResult.Errors == null)
                              {
                                  throw new ArgumentException("identityResult.Errors should not be null.");
                              }
                              string errorMsg = string.Join(',', identityResult.Errors.Select(r => r.Description));
                      
                              _logger.LogInformation(errorMsg);
                      
                              return Results.BadRequest(errorMsg);
                          }
                      
                          /// <summary>
                          /// 登录
                          /// </summary>
                          /// <param name="userLoginInfo"></param>
                          /// <returns></returns>
                          [HttpPost("login")]
                          public async Task<IResult> LoginAsync([FromBody] UserLoginInput userLoginInfo)
                          {
                              _logger.LogInformation("JwtLogin Begin");
                              var result = await _signInManager.PasswordSignInAsync(userLoginInfo.Email, userLoginInfo.Password, userLoginInfo.RememberMe, lockoutOnFailure: false);
                      
                              if (result.Succeeded)
                              {
                                  AppUser user = await _userManager.FindByEmailAsync(userLoginInfo.Email);
                      
                                  //创建Token等等
                                  var token = Guid.NewGuid().ToString();
                      
                                  _logger.LogInformation($"User {userLoginInfo},Login Success");
                      
                                  return Results.Ok(token);
                              }
                              else
                              {
                                  return Results.BadRequest(result.ToString());
                              }
                          }
                      }
                      
                      /// <summary>
                      /// 创建用户实体
                      /// </summary>
                      /// <param name="FirstName">姓</param>
                      /// <param name="LastName">名</param>
                      /// <param name="Email">邮件、登录名</param>
                      /// <param name="Password">密码</param>
                      public record CreateAppUser(string FirstName, string LastName, string Email, string Password);
                      
                      /// <summary>
                      /// 
                      /// </summary>
                      /// <param name="Email">邮件、登录名</param>
                      /// <param name="Password">密码</param>
                      /// <param name="RememberMe">记住密码</param>
                      public record UserLoginInput(string Email, string Password, bool RememberMe);
                      
                      1
                      2
                      3
                      4
                      5
                      6
                      7
                      8
                      9
                      10
                      11
                      12
                      13
                      14
                      15
                      16
                      17
                      18
                      19
                      20
                      21
                      22
                      23
                      24
                      25
                      26
                      27
                      28
                      29
                      30
                      31
                      32
                      33
                      34
                      35
                      36
                      37
                      38
                      39
                      40
                      41
                      42
                      43
                      44
                      45
                      46
                      47
                      48
                      49
                      50
                      51
                      52
                      53
                      54
                      55
                      56
                      57
                      58
                      59
                      60
                      61
                      62
                      63
                      64
                      65
                      66
                      67
                      68
                      69
                      70
                      71
                      72
                      73
                      74
                      75
                      76
                      77
                      78
                      79
                      80
                      81
                      82
                      83
                      84
                      85
                      86
                      87
                      88
                      89
                      90
                      91
                      92
                      93
                      94
                      95
                      96
                      97
                      98
                      99
                      100
                      101
                      102
                      103
                      104
                      105
                      106
                      107
                      108
                      109
                      110
                      111
                      112
                      113
                      edit icon在 GitHub 上编辑此页open in new window
                      上次编辑于: 2023/3/18 08:21:52
                      贡献者: igeekfan,IGeekFan
                      上一页
                      FreeKit Extras 扩展包
                      下一页
                      Email 邮件
                      MIT Licensed | Copyright © 2021-present luoyunchong
                      苏ICP备16046457号-1

                      该应用可以安装在你的 PC 或移动设备上。这将使该 Web 应用程序外观和行为与其他应用程序相同。它将在出现在应用程序列表中,并可以固定到主屏幕,开始菜单或任务栏。此 Web 应用程序还将能够与其他应用程序和你的操作系统安全地进行交互。

                      详情