IdentityServer4(六):集成ASP.NET Core Identity


此前我們已經使用EFCoreIdentityServer4相關配置寫入SqlServer,但是用戶數據還是寫死的TestUser,本篇將集成ASP.NET Core Identity,將用戶數據保存到SqlServer中,當然,您也可以使用自建的用戶數據庫。

開始前先安裝必要的nuget包

Install-Package Microsoft.AspNetCore.Identity.EntityFrameworkCore -Version 3.1.1
Install-Package Microsoft.EntityFrameworkCore.SqlServer -Version 3.1.1

添加上下文

public class AspNetAccountDbContext : IdentityDbContext<ApplicationUser>
{
    public AspNetAccountDbContext(DbContextOptions<AspNetAccountDbContext> options) : base(options)
    {
    }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);
    }
}

向容器中添加服務

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<AspNetAccountDbContext>(options =>
    {
        options.UseSqlServer(Configuration.GetConnectionString("DefaultAspNetAccountConnection"));
    });
    services.AddIdentity<ApplicationUser, IdentityRole>()
        .AddEntityFrameworkStores<AspNetAccountDbContext>()
        .AddDefaultTokenProviders();
    services.Configure<IdentityOptions>(options =>
    {
    	// 密碼複雜度配置
        options.Password.RequireDigit = true;
        options.Password.RequiredLength = 6;
        options.Password.RequiredUniqueChars = 1;
        options.Password.RequireLowercase = false;
        options.Password.RequireNonAlphanumeric = false;
        options.Password.RequireUppercase = false;
    });
    // 爲了代碼簡單一點,後面的配置省略,可參考前文
}

登錄控制器的修改

刪除原先的TestUserStore,使用ASP.NET Core Identity進行操作

public class AccountController : Controller
{
    private UserManager<ApplicationUser> _userManager;
    private SignInManager<ApplicationUser> _signInManager;
    private IIdentityServerInteractionService _interaction;

    public AccountController(UserManager<ApplicationUser> userManager, SignInManager<ApplicationUser> signInManager, IIdentityServerInteractionService interaction)
    {
        _userManager = userManager;
        _signInManager = signInManager;
        _interaction = interaction;
    }
    public IActionResult Login(string returnUrl)
    {
        ViewData["ReturnUrl"] = returnUrl;
        return View();
    }
            [HttpPost]
    public async Task<IActionResult> Login(LoginViewModel loginViewModel, string returnUrl)
    {
        if (!ModelState.IsValid)
        {
            return View();
        }

        var user = await _userManager.FindByEmailAsync(loginViewModel.Email);
        if (user == null)
        {
            ModelState.AddModelError(nameof(loginViewModel.Email), $"Email {loginViewModel.Email} not exists");
        }
        else
        {
            if (await _userManager.CheckPasswordAsync(user, loginViewModel.Password))
            {
                AuthenticationProperties props = null;
                if (loginViewModel.RememberMe)
                {
                    props = new AuthenticationProperties
                    {
                        IsPersistent = true,
                        ExpiresUtc = DateTimeOffset.UtcNow.Add(TimeSpan.FromMinutes(30))
                    };
                }

                await _signInManager.SignInAsync(user, props);

                if (_interaction.IsValidReturnUrl(returnUrl))
                {
                    return Redirect(returnUrl);
                }
                return Redirect("~/");
            }
            ModelState.AddModelError(nameof(loginViewModel.Password), "Wrong password");
        }
        return View(loginViewModel);
    }
}

數據遷移

執行命令

add-migration InitialAspNetAccountDbMigration -c AspNetAccountDbContext -o Data/Migrations/Application/AspNetAccountDb

可以看到成功添加了遷移代碼
在這裏插入圖片描述
執行命令生成數據庫

update-database -c AspNetAccountDbContext

成功生成
在這裏插入圖片描述

播種默認用戶數據

public class SeedData
{
    public static void EnsureSeedAspNetAccountData(string connectionString)
    {
        var services = new ServiceCollection();
        services.AddLogging();
        services.AddDbContext<AspNetAccountDbContext>(options =>
        {
            options.UseSqlServer(connectionString);
        });

        services.AddIdentity<ApplicationUser, IdentityRole>()
            .AddEntityFrameworkStores<AspNetAccountDbContext>()
            .AddDefaultTokenProviders();

        services.Configure<IdentityOptions>(options =>
        {
            options.Password.RequireDigit = true;
            options.Password.RequiredLength = 6;
            options.Password.RequiredUniqueChars = 1;
            options.Password.RequireLowercase = false;
            options.Password.RequireNonAlphanumeric = false;
            options.Password.RequireUppercase = false;
        });

        using (var serviceProvider = services.BuildServiceProvider())
        {
            using (var scope = serviceProvider.GetRequiredService<IServiceScopeFactory>().CreateScope())
            {
                var context = scope.ServiceProvider.GetService<AspNetAccountDbContext>();
                context.Database.Migrate();

                var userManager = scope.ServiceProvider.GetRequiredService<UserManager<ApplicationUser>>();

                var zhangsan = userManager.FindByNameAsync("zhangsan").Result;
                if (zhangsan == null)
                {
                    zhangsan = new ApplicationUser
                    {
                        UserName = "zhangsan",
                        Email = "[email protected]"
                    };
                    var result = userManager.CreateAsync(zhangsan, "123456").Result;
                    if (!result.Succeeded)
                    {
                        throw new Exception(result.Errors.First().Description);
                    }
                    result = userManager.AddClaimsAsync(zhangsan, new Claim[] {
                        new Claim(JwtClaimTypes.Name, "張三"),
                        new Claim(JwtClaimTypes.GivenName, "三"),
                        new Claim(JwtClaimTypes.FamilyName, "張"),
                        new Claim(JwtClaimTypes.Email, "[email protected]"),
                        new Claim(JwtClaimTypes.EmailVerified, "true", ClaimValueTypes.Boolean),
                        new Claim(JwtClaimTypes.WebSite, "http://zhangsan.com"),
                        new Claim(JwtClaimTypes.Address, @"{ '城市': '杭州', '郵政編碼': '310000' }",
                            IdentityServer4.IdentityServerConstants.ClaimValueTypes.Json)
                    }).Result;

                    if (!result.Succeeded)
                    {
                        throw new Exception(result.Errors.First().Description);
                    }
                }
                // 爲了代碼簡單一點,刪除其他用戶數據
            }
        }
    }
}

當我們成功運行程序後,查看數據庫,可以看到種子數據已經插入
在這裏插入圖片描述

更多

可訪問GitHub查看源碼

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章