IdentityServer4-EF动态配置Client和对Claims授权(二)
原文:IdentityServer4-EF动态配置Client和对Claims授权(二)
本节介绍Client的ClientCredentials客户端模式,先看下画的草图:
一、在Server上添加动态新增Client的API 接口。
为了方便测试,在Server服务端中先添加swagger,添加流程可参考:https://www.cnblogs.com/suxinlcq/p/6757556.html
在ValuesController控制器中注入ConfigurationDbContext上下文,此上下文可用来加载或配置IdentityServer4.EntityFramework的Client、身份信息、API资源信息或CORS数据等。
在ValuesController中实添加以下代码:
private ConfigurationDbContext _context;public ValuesController(ConfigurationDbContext context){_context = context;}
添加动态新增Client的API接口:
[HttpPost]public IActionResult Post([FromBody] IdentityServer4.EntityFramework.Entities.Client client){var res = _context.Clients.Add(client);if(_context.SaveChanges() >0)return Ok(true);elsereturn Ok(false);}
控制器代码如下:
二、对Server上的API进行保护
(1)安装IdentityServer4.AccessTokenValidation包
(2)在startup.cs中ConfigureServices方法添加如下代码:
//protect API services.AddMvcCore().AddAuthorization().AddJsonFormatters();services.AddAuthentication("Bearer").AddIdentityServerAuthentication(options =>{options.Authority = "http://localhost:5000";options.RequireHttpsMetadata = false;options.ApiName = "api1";});
AddAuthentication把Bearer配置成默认模式,将身份认证服务添加到DI中。
AddIdentityServerAuthentication把IdentityServer的access token添加到DI中,供身份认证服务使用。
(3)在startup.cs中Configure方法添加如下代码:
public void Configure(IApplicationBuilder app, IHostingEnvironment env){//if (env.IsDevelopment())//{// app.UseDeveloperExceptionPage();//}//AddSwagger app.UseSwagger();app.UseSwaggerUI(c =>{c.SwaggerEndpoint("/swagger/v1/swagger.json", "Server接口文档");});InitializeDatabase(app);app.UseAuthentication();app.UseIdentityServer();app.UseMvc();}
UseAuthentication将身份验证中间件添加到管道中,以便在每次调用主机时自动执行身份验证。
(4)在ValuesController控制器中添加[Authorize]
(5)在项目属性->调试 中,启动浏览器,并设成swagger,如图:
(6)启动项目,并调用第一个Get接口。
显示Unauthorized(未授权),证明[Authorize]起作用了。
三、搭建Client客户端
(1)新建一个控制台程序,安装IdentityModel包。
(2)添加类IDSHelper.cs,添加客户端请求API接口代码。
public class IDSHelper{public static async Task MainAsync(){try{DiscoveryResponse disco = await DiscoveryClient.GetAsync("http://localhost:5000");if (disco.IsError){Console.WriteLine(disco.Error);return;}TokenClient tokenClient = new TokenClient(disco.TokenEndpoint, "Client", "secret");var tokenResponse = await tokenClient.RequestClientCredentialsAsync("api1");if (tokenResponse.IsError){Console.WriteLine(tokenResponse.Error);return;}Console.WriteLine(tokenResponse.Json);var client = new HttpClient();client.SetBearerToken(tokenResponse.AccessToken);var response = await client.GetAsync("http://localhost:5000/api/values/");if (!response.IsSuccessStatusCode){Console.WriteLine(response.StatusCode);}else{var content = await response.Content.ReadAsStringAsync();Console.WriteLine(content);}}catch (Exception ex){}} }
(3)修改Program.cs代码,如下:
class Program{static void Main(string[] args)=> IDSHelper.MainAsync().GetAwaiter().GetResult();}
(4)按Ctrl+F5,可以获取到access token和接口返回值
复制token,用postman调用,成功获取到了接口返回值。
四、测试动态新增Client接口
安装IdentityServer4包。
安装IdentityServer4.EntityFramework包。
在IDSHelper.cs类中添加Post方法:
public static async Task Post(){try{DiscoveryResponse disco = await DiscoveryClient.GetAsync("http://localhost:5000");if (disco.IsError){Console.WriteLine(disco.Error);return;}TokenClient tokenClient = new TokenClient(disco.TokenEndpoint, "Client", "secret");var tokenResponse = await tokenClient.RequestClientCredentialsAsync("api1");if (tokenResponse.IsError){Console.WriteLine(tokenResponse.Error);return;}Console.WriteLine(tokenResponse.Json);var client = new HttpClient();client.SetBearerToken(tokenResponse.AccessToken);Client c1 = new Client{ClientId = "Test",AllowedGrantTypes = GrantTypes.ClientCredentials,ClientSecrets ={new Secret("secret".Sha256())},AllowedScopes = { "api1" }};string strJson = JsonConvert.SerializeObject(c1 .ToEntity());HttpContent content = new StringContent(strJson);content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");//由HttpClient发出Post请求Task<HttpResponseMessage> response = client.PostAsync("http://localhost:5000/api/values/", content);if (response.Result.StatusCode != System.Net.HttpStatusCode.OK){Console.WriteLine(response.Result.StatusCode);}else{Console.WriteLine(response.Result.Content.ReadAsStringAsync().Result);}}catch (Exception ex){}}
顺便把main中改成对Post调用:
static void Main(string[] args)=> IDSHelper.Post().GetAwaiter().GetResult();
按Ctrl+F5,调用新增Client的接口,并成功返回true。
同时可以在数据库中的Client表找到相关记录。需要注意的是,不能添加相同Client ID的Client。
五、在Client中添加Claim信息,并在API接口中对Claim信息进行验证。
关于Claim的介绍可以看这篇文章:http://www.cnblogs.com/stulzq/p/8726002.html
这里把Claim简单当做用户的身份信息使用,修改Post方法里面的Client:
Client c1 = new Client{ClientId = "superAdmin",AllowedGrantTypes = GrantTypes.ClientCredentials,ClientSecrets ={new Secret("secret".Sha256())},AllowedScopes = { "api1" },Claims = new List<Claim>{new Claim(JwtClaimTypes.Role, "admin")}};
可以看出,Claims为List,可以是很多个角色,这里只添加一个。
Ctrl+F5,运行成功添加superAdmin Client。
现在,需要对Server服务端的新增Client接口进行Claim身份验证,添加如下代码:
[Authorize(Roles ="admin")]
然后再客户端修改授权的账号为superadmin。
TokenClient tokenClient = new TokenClient(disco.TokenEndpoint, "superAdmin", "secret");
Ctrl+F5运行
问题出现了,返回了Forbidden,没有权限进行访问。
这时候我们上官网查阅了资料,发现在添加Client的Claim时候,IdentityServer EntityFramework会为Claim的role添加一个默认前缀,为client_。所以,实际上它为client_role。
而服务端只能对role进行验证。
此时我们需要把Claim的默认前缀去掉,设置为空ClientClaimsPrefix = "" 。
去掉Server的Role验证,添加形如下面代码的Client。
Client c1 = new Client{ClientId = "adminClient",AllowedGrantTypes = GrantTypes.ClientCredentials,ClientSecrets ={new Secret("secret".Sha256())},AllowedScopes = { "api1" },Claims = new List<Claim>{new Claim(JwtClaimTypes.Role, "admin")},ClientClaimsPrefix = "" //把client_ 前缀去掉};
Ctrl+F5,运行成功添加adminClient Client,这次的是Role为admin。
然后重新再Server服务端加上[Authorize(Roles ="admin")]
同时修改验证账号为adminClient。
TokenClient tokenClient = new TokenClient(disco.TokenEndpoint, "adminClient", "secret");
最后运行程序,成功地在[Authorize(Roles ="admin")]权限下访问并新增了Client。
六、需要注意的问题
(1)新增Client到数据库时候,这里需要接收IdentityServer4.EntityFramework.Entities.Client
而不是IdentityServer4.Models.Client,否则API接口在接收和转化Client模型的时候会报错。
(2)此外,本节介绍的Client的AllowedGrantTypes 都为 GrantTypes.ClientCredentials,相应的,客户端请求是,需要用RequestClientCredentialsAsync方法。
最后再次提下,ClientCredentials模式的适用场景:用于和用户无关,服务与服务之间直接交互访问资源。
Server服务端源码地址:https://github.com/Bingjian-Zhu/Server
Client客户端源码地址:https://github.com/Bingjian-Zhu/Client
文中如有错漏,欢迎指正。
转载于:https://www.cnblogs.com/lonelyxmas/p/10199198.html
IdentityServer4-EF动态配置Client和对Claims授权(二)相关推荐
- IdentityServer4-从数据库获取User登录并对Claims授权验证(五)
本节将在第四节基础上介绍如何实现IdentityServer4从数据库获取User进行验证,并对Claim进行权限设置. 一.新建Web API资源服务,命名为ResourceAPI (1)新建API ...
- IdentityServer4-MVC+Hybrid实现Claims授权验证(四)
上节IdentityServer4-客户端的授权模式原理分析(三)以对话形式,大概说了几种客户端授权模式的原理,这节重点介绍Hybrid模式在MVC下的使用.且为实现IdentityServer4从数 ...
- kafka原理_Kafka动态配置实现原理解析
总 第19篇 2019年 第15篇 一.问题导读Apache Kafka在全球各个领域各大公司获得广泛使用,得益于它强大的功能和不断完善的生态.其中Kafka动态配置是一个比较高频好用的功能,下面我们 ...
- nginx动态配置及服务发现那些事
标题, <闲聊nginx动态配置及服务发现的那些事> - 这次的准备闲聊关于nginx服务发现的话题, 按照我以往写文章的性子,估计会迁移一些主题. 毕竟单纯聊nginx和动态服务发 ...
- ABP动态配置数据库连接字符串 Oracle11g数据库
ABP动态配置数据库连接 Oracle11g数据库 ABP的仓储关于数据库连接字符串的配置是从web.config(app.config)的connectionStrings读取的. 我想实现的功能是 ...
- ZooKeeper Dynamic Reconfiguration(ZooKeeper 动态配置重构)
Overview 概览 Prior to the 3.5.0 release, the membership and all other configuration parameters of Zoo ...
- Nacos的动态配置源码解析
文章目录 1. 如何使用 2. 原理详解 2.1 采用延迟线程池定时执行"监听"文件是否有修改 2.2 通过长轮询的方式获得修改过的文件及其内容 2.3 拿到配置后通过applic ...
- springboot整合Quartz实现动态配置定时任务
版权声明:本文为博主原创文章,转载请注明出处. https://blog.csdn.net/liuchuanhong1/article/details/60873295 前言 在我们日常的开发中,很多 ...
- Spring Boot 整合 Quartz 实现 Java 定时任务的动态配置
点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 首先说下这次主题,动态配置.没接触过定时任务的同学可以先看 ...
最新文章
- Redis为什么又引入了多线程?单线程不香了?
- CentOS7安装和配置samba
- POJ 3061 -- Subsequence(二分)
- Hadoop系列(三)MapReduce Job的几种提交运行模式
- 2006年4月全国计算机等级考试二级Java语言程序设计
- 针对故障场景的血液,汗液和书写自动集成测试
- scala重载无参构造方法_Scala中的无参数方法
- Android蓝牙A2DP连接实现
- 启动程序端口被占用Address already in use: bind解决方案
- redirect()重新定向·
- WPS简历模板的图标怎么修改_新媒体运营-简历模板范文,【工作经历+项目经验+自我评价】怎么写?...
- 全量、增量 数据抽取 同步
- tomcat 窗口中文乱码解决
- Linux命令行运行多线程程序 和 QT集成IDE下运行多线程程序的问题。
- 以前看的关于物联网的总结
- 网络攻防--网络防御技术(一)
- 欢迎进入GeekYang博客导航一站式搜索(所有博客的汇总帖)
- Python-正则表达式
- orbslam2稠密地图转octomap
- matlab绘制单摆相图,单摆运动―相图.ppt