IdentityServer4实战:持久化 Resource

前言

在前几篇的学习中,我们定义的 ApiResource、ApiScope、IdentityResource 都是存储在内存中的,通过 AddInMemoryApiScopes(Startup.GetApiScopes())、AddInMemoryIdentityResources(Startup.GetIdentityResources())、 AddInMemoryApiResources(Startup.GetApiResources()) 的方式注入到 IDS4 的服务中。本篇我们学习如何使用数据库或其他持久化方法存储和读取 Resource 。

IdentityServer4 中 Resource 概念

在 IdentityServer4 中一共有3种资源类型:IdentityResource、ApiResource、ApiScope,定义这些资源的名称必须是唯一的,不可重复。

IdentityResource

身份资源,表示关于用户的声明,如用户ID、显示名、电子邮件地址等。

ApiResource

对 ApiScope 高层分组(归类)。当 API 资源变大时,使用 ApiScope 作用域列表可能不可行。通常需要引入某种名称空间来组织作用域名称,可能还希望将它们分组在一起,并获得一些更高级的构造,如访问令牌中的受众声明。如:多个资源应该支持相同的作用域名称,但是有时您显式地希望将一个作用域隔离到某个资源。 在IdentityServer中,ApiResource类允许一些额外的组织

ApiScope

资源作用域。

IResourceStore 接口

IDS4 为开发者定义了一个 IResourceStore 接口,实现该接口即可做自己的 Resource 持久化存储和读取。

CustomerResourceStore 实现

新建 CustomerResourceStore 类,实现 IResourceStore 接口,写我们自己的资源查找规则。

为了简单,笔者使用的 Resource 全部是已赋值好的内容,笔友可以通过数据库或其他持久化介质获取 Resource。

FindIdentityResourcesByScopeNameAsync

1

2

3

4

5

6

7

/// <summary>

        /// 身份资源

        /// </summary>

        private readonly List<IdentityResource> identityResources = new List<IdentityResource> {

            new IdentityResources.OpenId(),

            new IdentityResources.Profile()

        };

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

/// <summary>

        /// 通过 名称 查找符合要求的 IdentityResources

        /// </summary>

        /// <param name="scopeNames"></param>

        /// <returns></returns>

        public async Task<IEnumerable<IdentityResource>> FindIdentityResourcesByScopeNameAsync(IEnumerable<string> scopeNames)

        {

            var result = new List<IdentityResource>();

 

            foreach (var name in scopeNames)

            {

                if (identityResources.Count(t => t.Name == name) > 0)

                {

                    result.Add(identityResources.First(t => t.Name == name));

                }

            }

 

            return result;

        }

FindApiResourcesByNameAsync

1

2

3

4

5

6

7

8

9

10

11

/// <summary>

        /// ApiResource 资源

        /// </summary>

        private readonly List<ApiResource> apiResources = new List<ApiResource> {

            new ApiResource("admin""用户管理"){

                Scopes = { "user.list" "user.delete" }

            },

            new ApiResource("article""文章管理"){

                Scopes = { "article.list" "article.delete" }

            },

        };

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

/// <summary>

        /// 通过 名称 查找符合要求的 ApiResources

        /// </summary>

        /// <param name="apiResourceNames"></param>

        /// <returns></returns>

        public async Task<IEnumerable<ApiResource>> FindApiResourcesByNameAsync(IEnumerable<string> apiResourceNames)

        {

            var result = new List<ApiResource>();

 

            foreach (var name in apiResourceNames)

            {

                if (apiResources.Count(t=>t.Name== name) > 0)

                {

                    result.Add(apiResources.First(t => t.Name == name));

                }

            }

 

            return result;

        }

FindApiScopesByNameAsync

1

2

3

4

5

6

7

8

9

10

/// <summary>

        /// ApiScope 资源

        /// </summary>

        private readonly List<ApiScope> apiScopeResources = new List<ApiScope> {

            new ApiScope("article.list""文章-查看"),

            new ApiScope("article.delete""文章-删除"),

 

            new ApiScope("user.list""用户-查看"),

            new ApiScope("user.delete""部门-删除"),

        };

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

/// <summary>

        /// 通过 名称 查找符合要求的 ApiScopes

        /// </summary>

        /// <param name="scopeNames"></param>

        /// <returns></returns>

        public async Task<IEnumerable<ApiScope>> FindApiScopesByNameAsync(IEnumerable<string> scopeNames)

        {

            var result = new List<ApiScope>();

 

            foreach (var name in scopeNames)

            {

                if (apiScopeResources.Count(t => t.Name == name) > 0)

                {

                    result.Add(apiScopeResources.First(t => t.Name == name));

                }

            }

 

            return result;

        }

FindApiResourcesByScopeNameAsync

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

/// <summary>

        /// 通过 作用域名称 查找符合要求的 ApiResources

        /// </summary>

        /// <param name="scopeNames"></param>

        /// <returns></returns>

        public async Task<IEnumerable<ApiResource>> FindApiResourcesByScopeNameAsync(IEnumerable<string> scopeNames)

        {

            var result = new List<ApiResource>();

 

            foreach (var name in scopeNames)

            {

                foreach (var apiResource in apiResources)

                {

                    if (apiResource.Scopes.Contains(name) && result.Count(t=>t.Name == name) ==0)

                    {

                        result.Add(apiResource);

                    }

                }

            }

 

            return result;

        }

GetAllResourcesAsync

1

2

3

4

5

6

7

8

/// <summary>

        /// 返回所有的资源

        /// </summary>

        /// <returns></returns>

        public  async Task<Resources> GetAllResourcesAsync()

        {

            return new Resources(identityResources, apiResources, apiScopeResources);

        }

修改 Client 的 AllowedScopes

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

new Client

                    {

                        ClientId = "client2",

 

                        //  用户名 密码 模式

                        AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,

 

                        // 用于认证的密码

                        ClientSecrets =

                        {

                            new Secret("secret".Sha256())

                        },

                        // 客户端有权访问的范围(Scopes)

                        AllowedScopes = {

                            "openid"

                            "profile" ,

                            "article.list" ,

                            "article.delete" ,

                            "user.list" ,

                            "user.delete"

                        }

                    }

删除注入的内存资源服务

PostMan 测试

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
要保证RabbitMQ消息持久化,需要在以下几个方面进行配置: 1. Exchange和Queue的持久化:在RabbitMQ中,Exchange和Queue默认情况下是非持久化的,也就是说它们只存在于内存中,当RabbitMQ服务器重启时,这些非持久化的Exchange和Queue将被删除。为了实现Exchange和Queue的持久化,需要在创建Exchange和Queue时将其标记为持久化。 2. 消息的投递模式:消息持久化需要将消息先存储在磁盘上,然后再进行投递。因此,需要将消息的投递模式设置为"持久化"。 3. 消息的确认模式:为了确保消息被正确地投递并存储在磁盘上,需要启用消息的确认模式。消息确认模式有两种:Publisher Confirmation和Consumer Acknowledgement。 下面是保证RabbitMQ消息持久化的具体方法: 1. Exchange和Queue的持久化: ```java // 创建Exchange和Queue时设置为持久化 channel.exchangeDeclare("exchange_name", "direct", true); channel.queueDeclare("queue_name", true, false, false, null); // 将Queue绑定到Exchange上 channel.queueBind("queue_name", "exchange_name", "routing_key"); ``` 2. 消息的投递模式: ```java // 将消息设置为持久化 byte[] messageBytes = "Hello, RabbitMQ!".getBytes(); BasicProperties properties = new BasicProperties().builder() .deliveryMode(2) // 持久化消息 .build(); // 发送消息到持久化的Queue channel.basicPublish("exchange_name", "queue_name", properties, messageBytes); ``` 3. 消息的确认模式: ```java // 启用Publisher Confirmation模式 channel.confirmSelect(); // 发送消息到持久化的Queue,并等待确认 channel.basicPublish("exchange_name", "queue_name", properties, messageBytes); if (!channel.waitForConfirms()) { // 消息发送失败 System.out.println("Message send failed!"); } // 启用Consumer Acknowledgement模式 channel.basicConsume("queue_name", false, new DefaultConsumer(channel) { @Override public void handleDelivery(String consumerTag, Envelope envelope, BasicProperties properties, byte[] body) throws IOException { // 处理消息 // 发送确认消息 channel.basicAck(envelope.getDeliveryTag(), false); } }); ``` 需要注意的是,以上三个方面都需要进行配置才能保证RabbitMQ消息的持久化,并且在消费者处理消息时,需要发送确认消息来确认消息已经被消费。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值