IdentityServer4结合Mysql

IdentityServer4结合Mysql前面写的示例中 IdeneityServ 使用的是内存缓存的存储方式 所有的配置都写在 Config cs 里 在实际应用中 应该使用数据库存储方式 方便随时配置 如添加新的用户 资源 客户端 也可以节省服务器内存 本文从三个方面来实现 IdentityServ 结合 Mysql 实现数据库存储方式 分别是客户端及资源数据 令牌及授权码数据以及用户数据 一 准备内容 1 准备 MySql 数据库服务器 新建一个空的数据库 2 IdentityServ 需要安装以下几个程序包 1 2

前面写的示例中,IdeneityServer使用的是内存缓存的存储方式,所有的配置都写在Config.cs里。在实际应用中,应该使用数据库存储方式,方便随时配置,如添加新的用户、资源、客户端,也可以节省服务器内存。

本文从三个方面来实现IdentityServer4结合Mysql实现数据库存储方式,分别是客户端及资源数据、令牌及授权码数据以及用户数据。

一,准备内容

1,准备MySql数据库服务器,新建一个空的数据库

2,IdentityServer需要安装以下几个程序包。

1

2

3

IdentityServer4.EntityFramework

Microsoft.EntityFrameworkCore.Tools

Pomelo.EntityFrameworkCore.MySql(也可以用MySql官方程序包:MySql.Data.EntityFrameworkCore)

3,appsettings.json添加数据库连接字符串

1

2

3

4

5

{

  "ConnectionStrings": {

    "MySqlDbConnectString""server=IP;userid=mysqlUserName;pwd=user's password;database=database name;connectiontimeout=30;Pooling=true;Max Pool Size=300; Min Pool Size=5;"

  }

}  

二,客户端及资源的数据库存储

前面我们使用AddInMemory的方式加载配置数据

1

2

3

AddInMemoryIdentityResources(Config.GetIdentityResources())

AddInMemoryApiResources(Config.GetApis())

AddInMemoryClients(Config.GetClients())

把这三行代码注释掉,以下代码替换

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

var connection = Configuration.GetConnectionString("MySqlDbConnectString");

          var builder = services.AddIdentityServer()

              //身份信息资源

              //.AddInMemoryIdentityResources(Config.GetIdentityResources())

              .AddConfigurationStore(opt =>

              {

                  opt.ConfigureDbContext = context =>

                  {

                      context.UseMySql(connection, sql =>

                      {

                          sql.MigrationsAssembly("IdentityServer");

                      });

                  };

              })

              .AddTestUsers(Config.GetUsers());}

要从数据库查询配置数据,肯定得添加相应的数据表,把IdentityServer项目设为启动项目,打开程序包管理器控制台,设置控制台默认项目为IdentityServer,在控制台输入以下指令

1

2

3

4

PM> add-migration ConfigDbContext -c ConfigurationDbContext  -o Data/Migrations/IdentityServer/PersistedGrantDb

To undo this action, use Remove-Migration.

PM> update-database

Done.

-c ConfigurationDbContext是指定当前的数据库上下文。ConfigurationDbContext定义在命名空间: IdentityServer4.EntityFramework.DbContexts,和昨们使用CodeFirst一样,定义了客户端及资源的数据表及表关联。add-migration生成迁移变动记录,update-datase更新数据库到最新状态。

IdentityServer4结合Mysql

 

 

 但是现在数据库中的客户端和资源数据都是为空的,需要把Config的配置数据添加到数据库,可以在Start.cs中添加方法进行数据库初始化

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

private void InitializeDatabase(IApplicationBuilder app)

       {

           using (var serviceScope = app.ApplicationServices.GetService

().CreateScope())

           {

               var context = serviceScope.ServiceProvider.GetRequiredService

();

               if (!context.Clients.Any())

               {

                   foreach (var client in Config.GetClients())

                   {

                       context.Clients.Add(client.ToEntity());

                   }

                   context.SaveChanges();

               }

 

               if (!context.IdentityResources.Any())

               {

                   foreach (var resource in Config.GetIdentityResources())

                   {

                       context.IdentityResources.Add(resource.ToEntity());

                   }

                   context.SaveChanges();

               }

 

               if (!context.ApiResources.Any())

               {

                   foreach (var resource in Config.GetApis())

                   {

                       context.ApiResources.Add(resource.ToEntity());

                   }

                   context.SaveChanges();

               }

           }

       }

说明:利用app.ApplicationServices.GetService

().CreateScope创建一个新的服务作用域与其他作用域隔离开,不影响其它作用域的上下文释放,操作实体更新数据库和我们平时用的一样。运行程序后,发现数据库已经有数据了

IdentityServer4结合Mysql

 

 

 运行IdentityServer,IdentityMvc,IdentityApi三个程序进行测试

IdentityServer4结合Mysql

 

 

二,令牌和授权码的数据库存储

利用IIdentityServerBuilder的扩写方法AddOperationalStore

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

//客户端及资源数据库存储配置

                .AddConfigurationStore(opt =>

                {

                    opt.ConfigureDbContext = context =>

                    {

                        context.UseMySql(connection, sql =>

                        {

                            sql.MigrationsAssembly("IdentityServer");

                        });

                    };

                })

                //令牌及授权码数据库存储配置

                .AddOperationalStore(opt =>

                {

                    opt.ConfigureDbContext = context =>

                    {

                        context.UseMySql(connection, sql =>

                        {

                            sql.MigrationsAssembly("IdentityServer");

                        });

                    };

                    opt.EnableTokenCleanup = true;

                    opt.TokenCleanupInterval = 30;

                })

                .AddTestUsers(Config.GetUsers());

 同样的,需要添加用来存储的数据表

1

2

3

4

PM> add-migration OperationContext -c PersistedGrantDbContext -o Data/Migrations/IdentityServer/OperationDb

Multiple startup projects set.

PM> update-database -c PersistedGrantDbContext

Done.

  运行IdentityServer,IdentityMvc,IdentityApi三个程序进行测试

IdentityServer4结合Mysql

 

 

 三,用户的数据库存储

IdentityServer4为IIdentityServerBuilder提供了支持客户端和资源数据库存储的AddConfigurationStore方法,支持令牌和授权码数据库存储的AddOperationalStore,但没有提供用户数据库存储的方法。我想是因为客户端、资源、令牌、授权码的存储结构是强制规定的,而用户不是,每个人定义用户的资源、角色、权限、基础信息的存储结构等各不相同。不过没有关系,可以自己仿AddConfigurationStore写一个支持用户数据库存储的AddUserStore方法.

在IdentityServer项目新建一个名为IdentityUserStore的文件夹,创建四个类

IdentityServer.IdentityUserStore.IdentityUser:用户实体

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

public class IdentityUser

    {

        [Key]

        [Required]

        public string SubjectId { getset; }

        [Required]

        public string Username { getset; }

        [Required]

        public string Password { getset; }

        public string ProviderName { getset; }

        public string ProviderSubjectId { getset; }

        public bool IsActive { getset; }
      
public ICollection

IdentityUserClaims { 
getset; }

    }

    public class IdentityUserClaim

    {

        [Key]

        public string ClaimId { getset; }

        [Required]

        public string Name { getset; }

        [Required]

        public string Value { getset; }

        [Required]

        public string UserSubjectId { getset; }

        [ForeignKey("UserSubjectId")]

        public virtual IdentityUser IdentityUser { getset; }

    }

IdentityServer.IdentityUserStore.UserStoreDbContext:用于定义数据库操作上下文,作用和前面使用过的ConfigurationDbContext、PersistedGrantDbContext一样

1

2

3

4

5

6

7

8

9

public class UserStoreDbContext:DbContext

   {

       public UserStoreDbContext(DbContextOptions opt) : base(opt)

       {

            

       }

       public DbSet

IdentityUser { 
getset; }

       public DbSet

IdentityUserClaim { 
getset; }

   }

IdentityServer.IdentityUserStore.UserStore:用于查询用户信息和验证登录密码

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

public class UserStore

   {

       private readonly UserStoreDbContext _dbContext;

       public UserStore(UserStoreDbContext dbContext)

       {

           _dbContext = dbContext;

       }

       ///

       /// 根据SubjectID查询用户信息

       ///

       /// 用户id

       ///

       public IdentityUser FindBySubjectId(string subjectId) {

           return _dbContext.Set

().Where(r => r.SubjectId.Equals(subjectId)).Include(r => r.IdentityUserClaims).SingleOrDefault();

       }

       ///

       /// 根据用户名查询用户

       ///

       /// 用户

       ///

       public IdentityUser FindByUsername(string username)

       {

           return _dbContext.Set

().Where(r => r.Username.Equals(username)).Include(r => r.IdentityUserClaims).SingleOrDefault();

       }

       ///

       /// 验证登录密码

       ///

       ///

       ///

       ///

       public bool ValidateCredentials(string username, string password)

       {

           password = Config.MD5Str(password);

           var user = _dbContext.Set

().Where(r => r.Username.Equals(username)

           &&r.Password.Equals(password)).Include(r => r.IdentityUserClaims).SingleOrDefault();

           return user != null;

       }

   }

  IdentityServer.IdentityUserStore.IIdentityServerBuilderUserStoreExtensions:对IIdentityServerBuilder的扩写,添加UserStoreDbContext、UserStoreDbContext的服务依赖。

1

2

3

4

5

6

7

8

9

public static class IIdentityServerBuilderUserStoreExtensions

  {

      public static IIdentityServerBuilder AddUserStore(this IIdentityServerBuilder builder, Action

userStoreOptions = 
null)

      {

          builder.Services.AddDbContext

(userStoreOptions);

          builder.Services.AddTransient

();

          return builder;

      }

  }

 在Startup.ConfigureServices方法中以下面代码替换AddTestUser(Config.GetUsers)

1

2

3

4

5

6

7

8

//.AddTestUsers(Config.GetUsers())

      .AddUserStore(opt =>

      {

          opt.UseMySql(connection, sql =>

          {

              sql.MigrationsAssembly("IdentityServer");

          });

      })

添加用户存储数据表,在程序包管理器中输入以下指令

1

2

3

4

5

6

PM> add-migration UserStoreContext -c UserStoreDbContext -o Data/Migrations/IdentityServer/UserDb

PM> update-database -c UserStoreDbContext

Multiple startup projects set.

Using project 'src\IdentityServer' as the startup project.

Done.

PM>

在数据库初始方法中添加Config类中的用户数据

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

private void InitializeDatabase(IApplicationBuilder app)

       {

           using (var serviceScope = app.ApplicationServices.GetService

().CreateScope())

           {

               var context = serviceScope.ServiceProvider.GetRequiredService

();

               var userContext = serviceScope.ServiceProvider.GetRequiredService

();

               //添加config中的客户端数据到数据库

               if (!context.Clients.Any())

               {

                   foreach (var client in Config.GetClients())

                   {

                       context.Clients.Add(client.ToEntity());

                   }

                   context.SaveChanges();

               }

               //添加config中的IdentityResources数据到数据库

               if (!context.IdentityResources.Any())

               {

                   foreach (var resource in Config.GetIdentityResources())

                   {

                       context.IdentityResources.Add(resource.ToEntity());

                   }

                   context.SaveChanges();

               }

               //添加config中的ApiResources数据到数据库

               if (!context.ApiResources.Any())

               {

                   foreach (var resource in Config.GetApis())

                   {

                       context.ApiResources.Add(resource.ToEntity());

                   }

                   context.SaveChanges();

               }

               //添加config中的Users数据到数据库

               if (!userContext.IdentityUser.Any())

               {

                   int index = 0;

                   foreach(var user in Config.GetUsers())

                   {

                       IdentityUser iuser = new IdentityUser()

                       {

                           IsActive = user.IsActive,

                           Password = user.Password,

                           ProviderName = user.ProviderName,

                           ProviderSubjectId = user.ProviderSubjectId,

                           SubjectId = user.SubjectId,

                           Username = user.Username,

                           IdentityUserClaims = user.Claims.Select(r => new IdentityUserClaim()

                           {

                               ClaimId = (index++).ToString(),

                               Name = r.Type,

                               Value = r.Value

                           }).ToList()

                       };

                       userContext.IdentityUser.Add(iuser);

                   }

                   userContext.SaveChanges();

               }

           }

       }

   可以看到数据库已经有用户数据了

IdentityServer4结合Mysql

 

 最后一步,登录时改用上面新建的UserStore类来验证登录密码以及查询用户信息,并添加用户Claim。

AccountController构造函数

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

//private readonly TestUserStore _users; 这里改成了UserStore

       private readonly UserStore _users;

       private readonly IIdentityServerInteractionService _interaction;

       private readonly IClientStore _clientStore;

       private readonly IAuthenticationSchemeProvider _schemeProvider;

       private readonly IEventService _events;

       public AccountController(

           IIdentityServerInteractionService interaction,

           IClientStore clientStore,

           IAuthenticationSchemeProvider schemeProvider,

           IEventService events,

           //TestUserStore _users=null,这里改成了UserStore

           UserStore users)

       {

           // _users = User ?? new TestUserStore(Config.GetUsers()); 这里改成了UserStore

           _users = users;

           _interaction = interaction;

           _clientStore = clientStore;

           _schemeProvider = schemeProvider;

           _events = events;

       }

 Task

Login(LoginInputModel model, string button),登录时把数据库中的IdentityUserClaims数据转化为Claim数据传入登录重载方法。

1

2

List

claims = user.IdentityUserClaims.Select(r => 
new Claim(r.Name,r.Value) ).ToList();

await HttpContext.SignInAsync(user.SubjectId, user.Username, props, claims.ToArray());

  运行IdentityServer,IdentityApi,IdentityMvc三个项目后进行登录授权-获取access_token-访问api

IdentityServer4结合Mysql

 

 

 

  

  

  

  

 

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/199133.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月26日 下午1:46
下一篇 2026年3月26日 下午1:47


相关推荐

  • static声明静态外部类_static静态变量的理解

    static声明静态外部类_static静态变量的理解在一个类中创建另外一个类,叫做成员内部类。这个成员内部类可以静态的(利用static关键字修饰),也可以是非静态的。由于静态的内部类在定义、使用的时候会有种种的限制。所以在实际工作中用到的并不多。   在开发过程中,内部类中使用的最多的还是非静态地成员内部类。不过在特定的情况下,静态内部类也能够发挥其独特的作用。    一、静态内部类的使用目的。    在定义内部类的时候,可以

    2022年10月11日
    8
  • Kotlin与Java的异同(一)

    Kotlin与Java的异同(一)Kotlin简介Kotlin是一种针对Java平台的新编程语言。Kotlin简洁、安全、务实,并且专注于与Java代码的互操作性。它几乎可以用在现在Java使用的任何地方:服务端开发、Android应用等等。Kotlin可以很好地和所有现存的Java库和框架一起工作,而且性能和Java旗鼓相当。Kotlin特点:Kotlin是静态类型语言并支持类型推导,允许维护正确性与性能的同时保…

    2022年7月7日
    47
  • 卸载jdk1.7

    卸载jdk1.7卸载jdk1.7:1、开始->程序->控制面板->卸载程序->程序和功能2、找到jdk的两个程序:java7update45和java(TM)SEDevelopmentKit73、右键->卸载转载于:https://www.cnblogs.com/Noul/p/10406623.html…

    2022年6月25日
    56
  • C语言switch史上最详细的讲解

    C语言switch史上最详细的讲解原文链接 https github com shellhub blog issues 41C 语言 switch 史上最详细的讲解 switch 语句允许测试变量与值列表的相等性 每个值称之为案例或者 case 程序会检查 switch 后面的值并且与 case 后面的值比对 如果相等则执行后面的代码或代码块语法 switch 在 C 语言中的语法如下 switch expression cas

    2026年3月26日
    2
  • 数字图像处理(17): 直方图均衡化处理

    数字图像处理(17): 直方图均衡化处理目录 1 直方图均衡化简介 1 1 直方图均衡化概念 1 2 直方图均衡化的理论基础 1 3 直方图均衡化的步骤 1 4 直方图均衡化应用场景 2 直方图均衡化 equalizeHist 3matplotlib pyplot subplot 函数 4matplotlib pyplot imshow 函数 5 直方图均衡化对比参考资料 1 直方图均衡

    2026年3月26日
    3
  • Java二维数组的输出

    Java二维数组的输出Java二维数组的输出<1>(1)输出结果右对齐”%5d”publicclassHelloWorld{publicstaticvoidmain(String[]args){intmyArray[][]={{1,2},{7,2},{3,4}};for(inti=0;i<3;i++){for(intj=0;j<2;j++)System.out.p..

    2022年6月1日
    33

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号