.net 6下创建identityserver4的项目过程记录之【一】
首先声明一下,我是按照下面的教程来进行操作的:
.NET 6 集成 IdentityServer4+AspNetCore Identity 读取本地数据表用户 - 董川民 (dongchuanmin.com)
具体步骤记录如下:
一、新建空白项目
1、选择Asp.net Core Api项目,如下图
2、输入项目名称,如下图:
3、选择框架
二、添加引用的类库
1、IdentityServer4
2、IdentityServer4.AspNetIdentity
3、Microsoft.EntityFrameworkCore
选择6.0.12版本
4、Microsoft.AspNetCore.Identity.EntityFrameworkCore
选择6.0.12版本
5、Microsoft.EntityFrameworkCore.Design
选择6.0.12版本
6、Microsoft.EntityFrameworkCore.Tools
7、Pomelo.EntityFrameworkCore.MySql
8、NETCore.Encrypt【可以不用添加】
下面是安装需要的类库后的总体列表:
三、新建类库:IdpConfig.cs
由于原作者没有把api和client的配置放到数据库里,所以这里是这样配置的,代码如下:
using IdentityServer4; using IdentityServer4.Models; namespace TestIdentityServer4InNetCore6 { public static class IdpConfig { public static IEnumerable<IdentityResource> GetIdentityResources() { return new IdentityResource[] { new IdentityResources.OpenId(), new IdentityResources.Profile(), new IdentityResources.Address(), new IdentityResources.Phone(), new IdentityResources.Email() }; } public static IEnumerable<ApiResource> GetApiResources() { return new[] { new ApiResource("api1", "My API #1") { Scopes = { "scope1"} } }; } public static IEnumerable<Client> GetClients() { return new[] { new Client { ClientId = "client", AllowedGrantTypes = GrantTypes.ResourceOwnerPassword, ClientSecrets = { new Secret("secret".Sha256()) }, AllowedScopes = //允许当访问的资源 { "scope1", IdentityServerConstants.StandardScopes.OpenId, IdentityServerConstants.StandardScopes.Email, IdentityServerConstants.StandardScopes.Address, IdentityServerConstants.StandardScopes.Phone, IdentityServerConstants.StandardScopes.Profile } } }; } public static IEnumerable<ApiScope> GetScope() { return new ApiScope[] { new ApiScope("scope1"), new ApiScope("scope2"), }; } } }
四、新建类库:ApplicationUser.cs
此类库继承于IdentityUser,可以在上面扩展自己需要的用户的字段,代码如下:
using Microsoft.AspNetCore.Identity; using System.ComponentModel; namespace TestIdentityServer4InNetCore6 { public class ApplicationUser : IdentityUser { public string MySomething { get; set; } = ""; /// <summary> /// 创建时间 /// </summary> public DateTime CreateTime { get; set; } /// <summary> /// 创建人Id /// </summary> public string CreatorId { get; set; } = ""; /// <summary> /// 否已删除 /// </summary> public bool Deleted { get; set; } /// <summary> /// 姓名 /// </summary> public string RealName { get; set; } /// <summary> /// 性别 /// </summary> public Sex Sex { get; set; } /// <summary> /// 出生日期 /// </summary> public DateTime? Birthday { get; set; } /// <summary> /// 所属部门Id /// </summary> public string DepartmentId { get; set; } = ""; public string OtherData { get; set; } = ""; // 用户角色 用户权限 用户信息 用户登录tokens 重新绑定与父类的关系 命名必须和父类一致 public virtual ICollection<IdentityUserRole<string>> UserRoles { get; set; } public virtual ICollection<IdentityUserClaim<string>> Claims { get; set; } public virtual ICollection<IdentityUserLogin<string>> Logins { get; set; } public virtual ICollection<IdentityUserToken<string>> Tokens { get; set; } } public enum Sex { [Description("男")] Man = 1, [Description("女")] Woman = 0 } }
五、新建类库:MyPasswordHasher.cs
此类是处理密码加密和判断的,代码如下:
using Microsoft.AspNetCore.Identity; using NETCore.Encrypt.Extensions; namespace TestIdentityServer4InNetCore6 { public class MyPasswordHasher : PasswordHasher<ApplicationUser> { public override string HashPassword(ApplicationUser user, string password) { //PasswordHasher<ApplicationUser> ph = new PasswordHasher<ApplicationUser>(); //var pstr = ph.HashPassword(new ApplicationUser(), password); //return pstr; return password.MD5(); } public override PasswordVerificationResult VerifyHashedPassword(ApplicationUser user, string hashedPassword, string providedPassword) { if (providedPassword.MD5().Equals(hashedPassword)) { return PasswordVerificationResult.Success; } else { return PasswordVerificationResult.Failed; } } } }
六、新建类库:IdpDbContext.cs
此类库为数据库的上下文,在里面初始化了角色和用户和种子数据,主要是便于测试用,代码如下:
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; namespace TestIdentityServer4InNetCore6 { public class IdpDbContext : IdentityDbContext<ApplicationUser> { public IdpDbContext(DbContextOptions<IdpDbContext> opt) : base(opt) { } protected override void OnModelCreating(ModelBuilder builder) { base.OnModelCreating(builder); builder.Entity<ApplicationUser>().ToTable("ApplicationUsers"); MyPasswordHasher ph = new MyPasswordHasher(); #region 初始化用戶与角色的种子数据 //1. 更新用戶与角色的外鍵 builder.Entity<ApplicationUser>( u => u.HasMany(x => x.UserRoles).WithOne().HasForeignKey(ur => ur.UserId).IsRequired() ); //2. 添加管理员角色 var adminRoleId = "f8df1775-e889-46f4-acdd-421ec8d9ba64"; builder.Entity<IdentityRole>().HasData( new IdentityRole() { Id = adminRoleId, Name = "Admin", NormalizedName = "Admin".ToUpper() } ); //3. 添加用户 var adminUserId = "f8df1775-e889-46f4-acdd-421ec8d9ba65"; ApplicationUser adminUser = new ApplicationUser { Id = adminUserId, UserName = "admin", NormalizedUserName = "admin".ToUpper(), RealName = "admin", NormalizedEmail = "admin@qq.com".ToUpper(), Email = "admin@qq.com", TwoFactorEnabled = false, EmailConfirmed = true, PhoneNumber = "123456789", PhoneNumberConfirmed = false, }; adminUser.PasswordHash = ph.HashPassword(adminUser, "123456"); builder.Entity<ApplicationUser>().HasData(adminUser); //4. 给用户加入管理员角色 builder.Entity<IdentityUserRole<string>>().HasData( new IdentityUserRole<string>() { RoleId = adminRoleId, UserId = adminUserId } ); #endregion } } }
七、新建类库:MyUserManager.cs
继承于UserManager
using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Options; namespace TestIdentityServer4InNetCore6 { public class MyUserManager : UserManager<ApplicationUser> { public MyUserManager(IUserStore<ApplicationUser> store, IOptions<IdentityOptions> optionsAccessor, IPasswordHasher<ApplicationUser> passwordHasher, IEnumerable<IUserValidator<ApplicationUser>> userValidators, IEnumerable<IPasswordValidator<ApplicationUser>> passwordValidators, ILookupNormalizer keyNormalizer, IdentityErrorDescriber errors, IServiceProvider services, ILogger<UserManager<ApplicationUser>> logger) : base(store, optionsAccessor, new MyPasswordHasher(), userValidators, passwordValidators, keyNormalizer, errors, services, logger) { optionsAccessor.Value.Password.RequireDigit = false; optionsAccessor.Value.Password.RequiredLength = 4; optionsAccessor.Value.Password.RequireLowercase = false; optionsAccessor.Value.Password.RequireUppercase = false; optionsAccessor.Value.Password.RequireNonAlphanumeric = false; } } }
八、修改Program.cs类
主要是配置数据库和identityserver4,数据库连接字符串记得换成自己的,代码如下:
using IdentityModel; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using System.Security.Claims; using TestIdentityServer4InNetCore6; var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddControllers(); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); builder.Services.AddDbContext<IdpDbContext>(opt => { opt.UseMySql("server=127.0.0.1;Port=3306;database=testidentityserver;uid=root;pwd=123456;", new MySqlServerVersion(new Version(8, 0, 29))); }); builder.Services.AddIdentity<ApplicationUser, IdentityRole>() .AddUserManager<MyUserManager>() .AddEntityFrameworkStores<IdpDbContext>() .AddDefaultTokenProviders(); builder.Services.AddIdentityServer() .AddDeveloperSigningCredential() .AddInMemoryIdentityResources(IdpConfig.GetIdentityResources()) .AddInMemoryClients(IdpConfig.GetClients()) .AddInMemoryApiScopes(IdpConfig.GetScope()) .AddInMemoryApiResources(IdpConfig.GetApiResources()) //.AddResourceOwnerValidator<MyResourceOwnerPasswordValidator>() //这句可以打开自主验证登录用户 //.AddProfileService<MyProfileService>() .AddAspNetIdentity<ApplicationUser>(); var app = builder.Build(); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseIdentityServer(); app.UseAuthorization(); app.MapControllers(); app.Run();
九、新建mysql空数据库
数据库的名称为:testidentityserver【跟第八步里填写的数据库名称要保持一致】
十、执行数据迁移
1、打开“程序包管理器控制台”,输入“Add-Migration CreateIdentitySchema”命令,代码和截图如下:
Add-Migration CreateIdentitySchema
2、恢复数据库,输入“Update-Database”,如下图:
Update-Database
3、执行上一步的命令后,数据库里会自动创建如下表:
十、使用postman测试
1、启动当前api项目,启动成功后,界面如下:
2、使用postman调试
按照下图的填写参数,出现如下界面,表示运行成功