<九>集成ASP.NETCore Identity 作为授权账户持久到数据库

我们之前都是用Identityserver4的测试类把数据添加到内存了,目的是为了测试方便,

现在我们把用户的信息利用ASP.NET Identity的方式持久化到数据库中。

1、引入Identityserver4.AspNetIdentity,然后新建一个ApplicationUser,ApplicationRole的类

public class ApplicationUser : IdentityUser<string>//不加int的话是默认主键为guid
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    [Key]
    public override string Id { get; set; }

}

public class ApplicationUserRoles : IdentityRole<string>
{
  [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
  [Key]
  public override string Id { get; set; }
}

 

2、替换服务端stratup中 .AddTestUsers(Config.GetUsers().ToList()) 换成

public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});

services.AddDbContext<ApplicationDbContext>(options =>
{
options.UseSqlServer(Configuration.GetConnectionString("Conn"));
});

//配置Identity
services.AddIdentity<ApplicationUser, ApplicationUserRoles>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
//修改Identity密码强度设置配置
services.Configure<IdentityOptions>(options =>
{
options.Password.RequireLowercase = false; //需要小写
options.Password.RequireNonAlphanumeric = false; //需要字母
options.Password.RequireUppercase = false; //需要大写
options.Password.RequiredLength = 6;
});

services.AddIdentityServer().AddDeveloperSigningCredential()
.AddInMemoryApiResources(Config.GetApiResources())
.AddInMemoryApiScopes(Config.GetScopes())
.AddInMemoryClients(Config.GetClients())
// .AddTestUsers(Config.GetUsers().ToList())
.AddAspNetIdentity<ApplicationUser>()
.AddInMemoryIdentityResources(Config.GetIdentityResources());

services.AddControllersWithViews();
}

3、替换登录逻辑,将Testuser的登录逻辑换成Identity的登录逻辑

  public class AccountController : Controller
    {
        // private readonly TestUserStore _testUserStore;
        private readonly UserManager<ApplicationUser> _userManager;
        private readonly SignInManager<ApplicationUser> _signinManager;
        private readonly IIdentityServerInteractionService _InteractionService;
        public AccountController(UserManager<ApplicationUser> userManager, SignInManager<ApplicationUser> signinManager, IIdentityServerInteractionService identityServerInteractionService)
        {
            _userManager = userManager;
            _signinManager = signinManager;
            _InteractionService = identityServerInteractionService;
        }
        //public AccountController( TestUserStore testUserStore) 
        //{
        //    _testUserStore = testUserStore;       
        //}
        public IActionResult Index()
        {
            return View();
        }


        public IActionResult Login(string returnUrl = "/Home/Index")
        {
            ViewData["Rurl"] = returnUrl;
            return View();
        }

        /// <summary>
        /// post 登录请求
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public async Task<IActionResult> Login(LoginInputModel model)
        {
            if (!ModelState.IsValid)
            {
                return View();
            }
            var user = await _userManager.FindByNameAsync(model.Name);
            // var user = _testUserStore.FindByUsername(model.Username);
            if (user == null)
            {
                return View();
            }
            //if (_testUserStore.ValidateCredentials(model.Username, model.Password))
            if (await _userManager.CheckPasswordAsync(user, model.Password))
            {
                var props = new AuthenticationProperties
                {
                    IsPersistent = false,     //是否记住。默认不记住。可以根据前端的传值改。
                    ExpiresUtc = DateTimeOffset.UtcNow.Add(TimeSpan.FromMinutes(1))
                };
                // await HttpContext.SignInAsync(user.SubjectId, user.Username, props);
                //await AuthenticationManagerExtensions.SignInAsync(
                //    HttpContext,
                //    new IdentityServerUser(user.SubjectId),
                //    props
                //    );

                await _signinManager.SignInAsync(user, props);
                if (!string.IsNullOrEmpty(model.ReturnUrl))
                //if (_InteractionService.IsValidReturnUrl(model.ReturnUrl))
                {
                    return Redirect(model.ReturnUrl);
                }
                else
                {
                    return Redirect("~/");
                }
            }
            return View();
        }

        /// <summary>
        /// 退出登录
        /// </summary>
        /// <returns></returns>
        public async Task<IActionResult> Logout()
        {
            await _signinManager.SignOutAsync();
            return Redirect("/Login");
        }
    }

 4、新增一个data文件夹用于存放初始化 数据库的相关类 

public class ApplicationDbContext :IdentityDbContext<ApplicationUser,ApplicationUserRoles,string>
    {
        public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
        {

        }
    }

 种子文件:数据库没有数据时,运行的时候给添加一个默认账户

 public class ApplicationDbContextSeed
    {
        private UserManager<ApplicationUser> _userManager;
        private RoleManager<ApplicationUserRoles> _roleManager;

        public async Task SeedAsync(ApplicationDbContext context, IServiceProvider services)
        {
            if (!context.Roles.Any())
            {
                var role = new ApplicationUserRoles()
                {
                    Id="111",
                    Name = "Administrators",
                    NormalizedName = "Administrators"
                };
                _roleManager = services.GetRequiredService<RoleManager<ApplicationUserRoles>>();
                var result = await _roleManager.CreateAsync(role);
                if (!result.Succeeded)
                {
                    throw new Exception("初始默认角色失败:"+result.Errors.SelectMany(e=>e.Description));
                }
            }

            if (!context.Users.Any())
            {
                _userManager = services.GetRequiredService<UserManager<ApplicationUser>>();

                var defaultUser = new ApplicationUser
                {
                    Id="111111",
                    UserName = "Administrator",
                    Email = "11111111@qq.com",
                    NormalizedUserName = "admin",
                    SecurityStamp = "admin",
                 };


                var result = await _userManager.CreateAsync(defaultUser, "123456");
                await _userManager.AddToRoleAsync(defaultUser, "Administrators");
                if (!result.Succeeded)
                {
                    throw new Exception("初始默认用户失败:" + result.Errors.SelectMany(e => e.Description));
                }
            }
        }
    }

 在程序开始运行前执行种子文件

 public static class WebHostMigrationExtensions
    {
        public static IHost MigrateDbContext<TContext>(this IHost host, Action<TContext, IServiceProvider> sedder) where TContext : DbContext
        {
            using (var scope = host.Services.CreateScope())
            {//只在本区间内有效
                var services = scope.ServiceProvider;
                var logger = services.GetRequiredService<ILogger<TContext>>();
                var context = services.GetService<TContext>();

                try
                {
                    context.Database.Migrate();
                    sedder(context, services);

                    logger.LogInformation($"执行DBContext {typeof(TContext).Name} seed执行成功");
                }
                catch (Exception ex)
                {
                    logger.LogError(ex, $"执行DBContext {typeof(TContext).Name} seed方法失败");
                }
            }

            return host;
        }
    }

 在program中加入启动时运行种子文件

 public static void Main(string[] args)
        {
             CreateHostBuilder(args).Build()
             .MigrateDbContext<ApplicationDbContext>((context, services) =>
            {
                new ApplicationDbContextSeed().SeedAsync(context, services).Wait();
            })
            .Run();
        }

5、数据库迁移

1、 Add-Migration
2、 Update-Database 

运行完成后生成的数据库表

 

 至此全部配置完毕,运行程序,数据库会初始化一条数据。

 

 用该用户名和密码登录成功。

posted @ 2020-11-03 00:54  许轩霖  阅读(246)  评论(0)    收藏  举报