夫天地者,万物之逆旅;光阴者,百代之过客。而浮生若梦,为欢几何?
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

/// <summary>
        /// 身份资源
        /// </summary>
        private readonly List<IdentityResource> identityResources = new List<IdentityResource> {
            new IdentityResources.OpenId(),
            new IdentityResources.Profile()
        };
/// <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

/// <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" }
            },
        };
/// <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

/// <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", "部门-删除"),
        };
/// <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

/// <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

/// <summary>
        /// 返回所有的资源
        /// </summary>
        /// <returns></returns>
        public  async Task<Resources> GetAllResourcesAsync()
        {
            return new Resources(identityResources, apiResources, apiScopeResources);
        }

修改 Client 的 AllowedScopes

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 测试


作者:暗夜余晖

本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

0

支持

0

反对

posted @2021-4-8  拜读(831)

评论列表

评论内容:



喜欢请打赏

支付宝 微信

请放心支付