瑞星 发表于 2022-8-27 16:36:07

.Net6集成IdentityServer4 +AspNetCore Identity读取本地数据表用户 独立鉴

IdentityServer4 实现鉴权、授权,AspNetCore Identity实现数据库用户管理表直接生成。
ps:IdentityServer4文档上最后给的例子是 // 配置使用内存存储用户信息,但使用 EF 存储客户端和资源信息,
  我初步要实现的是 //数据库存储用户信息   内存存储资源   (下一步资源也放数据库  以后弄好了有机会更)
直接干活:
1.创建.Net6 API程序,一顿引用,包括
https://img2022.cnblogs.com/blog/1255709/202207/1255709-20220715124614149-1382981909.png
防止图片挂掉打一遍文字:
IdentityServer4、
IdengtityServer4.AspNetIdentity、
AspNetCore.Identity.EntityFrameWorkCore(生成数据库表用的)、
EntityFrameWork+Disign+Tool三件套 (缺了不能自动迁移)、
Pomelo.EntityFrameWorkCore.MySql(我是用的MySql,如果是SqlServer 不用这个用一个大概叫EF.Sqlserver的)、
Encrypt (加密MD5用的 不必须)、
下面那个是自带的。
2.建立数据库连接类
https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gifhttps://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif 1public class IdpDbContext : IdentityDbContext<ApplicationUser>
2   {
3         public IdpDbContext(DbContextOptions<IdpDbContext> opt) : base(opt)
4         {
5
6         }
7         protected override void OnModelCreating(ModelBuilder builder)
8         {
9             base.OnModelCreating(builder);
10             builder.Entity<ApplicationUser>().ToTable("ApplicationUsers");
11             #region #
12             //builder.Entity<IdentityUserLogin<string>>().ToTable("ApplicationLogins");
13             //builder.Entity<IdentityUserClaim<string>>().ToTable("ApplicationUserClaims");
14             //builder.Entity<ApplicationUserRole>().ToTable("ApplicationUserRoles");
15             //builder.Entity<IdentityUserToken<string>>().ToTable("ApplicationUserTokens");
16             //builder.Entity<ApplicationRole>().ToTable("ApplicationRoles");
17             //builder.Entity<IdentityRoleClaim<string>>().ToTable("ApplicationRoleClaims");
18             //builder.Entity<ApplicationUserRole>().HasKey(t => t.Id).HasName("PK_UserRole_ID_KEY");
19             #endregion
20
21             builder.Entity<ApplicationUser>().HasData(
22               new ApplicationUser()
23               {
24                     Id = Guid.NewGuid().ToString(),
25                     RealName = "alice1",
26                     UserName = "alice1",
27                     PasswordHash = "alice1"
28               });
29             #region 初始化用戶与角色的种子数据
30             //1. 更新用戶与角色的外鍵
31             builder.Entity<ApplicationUser>(
32               u => u.HasMany(x => x.UserRoles).WithOne().HasForeignKey(ur => ur.UserId).IsRequired()
33               );
34             //2. 添加管理员角色
35             var adminRoleId = "f8df1775-e889-46f4-acdd-421ec8d9ba64";
36             builder.Entity<IdentityRole>().HasData(
37               new IdentityRole()
38               {
39                     Id = adminRoleId,
40                     Name = "Admin",
41                     NormalizedName = "Admin".ToUpper()
42               }
43             );
44             //3. 添加用户
45             var adminUserId = "f8df1775-e889-46f4-acdd-421ec8d9ba65";
46             ApplicationUser adminUser = new ApplicationUser
47             {
48               Id = adminUserId,
49               UserName = "admin",
50               NormalizedUserName= "admin".ToUpper(),
51               RealName = "admin",
52               NormalizedEmail = "admin@qq.com".ToUpper(),
53               Email = "admin@qq.com",
54               TwoFactorEnabled = false,
55               EmailConfirmed = true,
56               PhoneNumber = "123456789",
57               PhoneNumberConfirmed = false,
58
59             };
60             MyPasswordHasher ph = new MyPasswordHasher();
61             adminUser.PasswordHash = ph.HashPassword(adminUser, "123456");
62             builder.Entity<ApplicationUser>().HasData(adminUser);
63             //4. 给用户加入管理员角色
64             builder.Entity<IdentityUserRole<string>>().HasData(
65               new IdentityUserRole<string>()
66               {
67                     RoleId = adminRoleId,
68                     UserId = adminUserId
69               }
70               );
71             #endregion
72
73         }
74   }View Code 
3.Program里开始加东西(如果是历史的Net版本,是在StartUp里):
直接代码

1 using Microsoft.AspNetCore.Identity;
2 using Microsoft.EntityFrameworkCore;
3 using MyIDP;
4 using MyIDP.Models;
5 using MyIDP.Permission;
6
7 var builder = WebApplication.CreateBuilder(args);
8
9 // Add services to the container.
10 builder.Services.AddControllers();
11 // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
12 builder.Services.AddEndpointsApiExplorer();
13 builder.Services.AddSwaggerGen();
14
15 //由此重要
16 builder.Services.AddDbContext<IdpDbContext>(opt =>
17 {
18   opt.UseMySql("server=127.0.0.1;Port=3306;database=AccountDb;uid=root;pwd=123456;", new MySqlServerVersion(new Version(8,0,29)));
19 });
20
21 builder.Services.AddIdentity<ApplicationUser, IdentityRole>()
22               .AddUserManager<MyUserManager>()
23               .AddEntityFrameworkStores<IdpDbContext>()
24               .AddDefaultTokenProviders();
25
26 builder.Services.AddIdentityServer()
27   .AddDeveloperSigningCredential()
28
29   .AddInMemoryIdentityResources(MyIDP.IdpConfig.GetIdentityResources())
30   .AddInMemoryClients(MyIDP.IdpConfig.GetClients())
31   .AddInMemoryApiScopes( MyIDP.IdpConfig.GetScope())
32   .AddInMemoryApiResources( MyIDP.IdpConfig.GetApiResources())    //.AddResourceOwnerValidator<MyResourceOwnerPasswordValidator>() //这句可以打开自主验证登录用户
33   //.AddProfileService<MyProfileService>()
34   .AddAspNetIdentity<ApplicationUser>()
35   //.AddTestUsers(new List<IdentityServer4.Test.TestUser>
36   //{
37   //    new IdentityServer4.Test.TestUser
38   //    {
39   //      SubjectId="123",
40   //      Username = "alice",
41   //      Password = "alice",
42   //      Claims = new List<Claim>() {
43   //            new Claim(JwtClaimTypes.Role, "superadmin"),
44   //            new Claim(JwtClaimTypes.Role, "admin")
45   //      }
46   //    }
47   //})
48   ;
49
50 var app = builder.Build();
51
52 // Configure the HTTP request pipeline.
53 if (app.Environment.IsDevelopment())
54 {
55   app.UseSwagger();
56   app.UseSwaggerUI();
57 }
58
59 app.UseIdentityServer();
60 app.UseAuthorization();
61 app.MapControllers();
62 app.Run();因为使用的是内存储存t鉴权信息的方式,所以建立IdentityServer4的配置类IdpConfig
https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gifhttps://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif 1public static class IdpConfig
2   {
3         public static IEnumerable<IdentityResource> GetIdentityResources()
4         {
5             return new IdentityResource[]
6             {
7               new IdentityResources.OpenId(),
8               new IdentityResources.Profile(),
9               new IdentityResources.Address(),
10               new IdentityResources.Phone(),
11               new IdentityResources.Email()
12             };
13         }
14
15         public static IEnumerable<ApiResource> GetApiResources()
16         {
17             //return new ApiResource[]
18             //{
19             //    new ApiResource("api1", "My API #1",new List<string>(){JwtClaimTypes.Role})
20             //};
21             //新写法
22             return new[]
23             {
24               new ApiResource("api1", "My API #1")
25               {
26                     Scopes = { "scope1"}
27               }
28             };
29         }
30
31         public static IEnumerable<Client> GetClients()
32         {
33             return new[]
34             {
35               #region MyRegion
36                  //// client credentials flow client
37               //new Client
38               //{
39               //    ClientId = "console client",
40               //    ClientName = "Client Credentials Client",
41
42               //    AllowedGrantTypes = GrantTypes.ClientCredentials,
43
44               //    ClientSecrets = { new Secret("511536EF-F270-4058-80CA-1C89C192F69A".Sha256()) },
45
46               //    AllowedScopes = { "api1" }
47               //},
48
49   #endregion
50               
51               // wpf client, password grant
52               new Client
53               {
54                     ClientId = "client",
55                     AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
56                     ClientSecrets =
57                     {
58                         new Secret("secret".Sha256())
59                     },
60                     AllowedScopes = //允许当访问的资源
61                     {
62                         "scope1",
63                         //"api1",
64                         IdentityServerConstants.StandardScopes.OpenId,
65                         IdentityServerConstants.StandardScopes.Email,
66                         IdentityServerConstants.StandardScopes.Address,
67                         IdentityServerConstants.StandardScopes.Phone,
68                         IdentityServerConstants.StandardScopes.Profile }
69               }
70             };
71         }
72
73         public static IEnumerable<ApiScope> GetScope()
74         {
75             return new ApiScope[] {
76               new ApiScope("scope1"),
77               new ApiScope("scope2"),
78             };
79         }
80   }View Code数据库的usernamager
https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gifhttps://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif 1 public class MyUserManager : UserManager<ApplicationUser>
2   {
3         public MyUserManager(IUserStore<ApplicationUser> store, IOptions<IdentityOptions> optionsAccessor, IPasswordHasher<ApplicationUser> passwordHasher,
4         IEnumerable<IUserValidator<ApplicationUser>> userValidators, IEnumerable<IPasswordValidator<ApplicationUser>> passwordValidators, ILookupNormalizer keyNormalizer, IdentityErrorDescriber errors, IServiceProvider services, ILogger<UserManager<ApplicationUser>> logger)
5            : base(store, optionsAccessor, new MyPasswordHasher(), userValidators, passwordValidators, keyNormalizer, errors, services, logger)
6         {
7             optionsAccessor.Value.Password.RequireDigit = false;
8             optionsAccessor.Value.Password.RequiredLength = 4;
9             optionsAccessor.Value.Password.RequireLowercase = false;
10             optionsAccessor.Value.Password.RequireUppercase = false;
11             optionsAccessor.Value.Password.RequireNonAlphanumeric = false;
12         }
13
14   }View Code重写验证密码的方法类MyResourceOwnerPasswordValidator,(如果没有打开Program中的AddResourceOwnerValidator() 则不需要)
https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gifhttps://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gifpublic class MyResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator
    {
      public readonly SignInManager<ApplicationUser> signInManager;
      private readonly MyUserManager userManager;
      //public readonly IEventService service;
      public MyResourceOwnerPasswordValidator(MyUserManager userService, SignInManager<ApplicationUser> signInManager)//, IEventService service)
      {
            userManager = userService;
            this.signInManager = signInManager;
            //this.service = service;

      }
      public async Task ValidateAsync(ResourceOwnerPasswordValidationContext context)
      {
            if (string.IsNullOrEmpty(context.UserName) || string.IsNullOrEmpty(context.Password))
            {
                context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, "验证被拒绝,用户名或者密码为空。");
                return;
            }
            var user = await userManager.FindByNameAsync(context.UserName);
            if (user == null)
            {
                context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, "验证失败,不存在当前用户。");
                return;
            }
            //检验用户密码(虽然我也不知道他的密码是采用什么加密方式得到的,但是我也不需要知道)
            var passwordPass = await userManager.CheckPasswordAsync(user, context.Password);
            if (!passwordPass)
            {
                context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, "验证失败,用户凭证错误");
                return;
            }
            else
            {
                try
                {
                  await userManager.AddLoginAsync(user, new UserLoginInfo(user.Id, "", user.UserName));
                }
                catch (Exception ex)
                {
                  ;
                }
                finally
                {
                  context.Result = new GrantValidationResult(user.Id, GrantType.ResourceOwnerPassword, new List<Claim>() { new Claim("account", user.UserName) });
                }
            }
            return;
      }

    }View CodeMyPasswordHasher
https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gifhttps://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif 1 public class MyPasswordHasher : PasswordHasher<ApplicationUser>
2   {
3         public override string HashPassword(ApplicationUser user, string password)
4         {
5             //PasswordHasher<ApplicationUser> ph = new PasswordHasher<ApplicationUser>();
6             //var pstr = ph.HashPassword(new ApplicationUser(), password);
7             //return pstr;
8             return password.MD5();
9         }
10
11         public override PasswordVerificationResult VerifyHashedPassword(ApplicationUser user, string hashedPassword, string providedPassword)
12         {
13             if (providedPassword.MD5().Equals(hashedPassword))
14             {
15               return PasswordVerificationResult.Success;
16             }
17             else
18             {
19               return PasswordVerificationResult.Failed;
20             }
21         }
22   }View Code创建自己的User类 ApplicationUser继承 IdentityUser  复写自带的AspNetUser表
https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gifhttps://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gifpublic 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
    {
      
      Man = 1,

      
      Woman = 0
    }View Code至此可以生成数据库迁移后 Postman测试一下
https://img2022.cnblogs.com/blog/1255709/202207/1255709-20220715131225166-975029694.png
 

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: .Net6集成IdentityServer4 +AspNetCore Identity读取本地数据表用户 独立鉴