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() >)
return Ok(true);
else
return 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
IdentityServer4-EF动态配置Client和对Claims授权(二)的更多相关文章
- Spring动态配置多数据源
Spring动态配置多数据源,即在大型应用中对数据进行切分,并且采用多个数据库实例进行管理,这样可以有效提高系统的水平伸缩性.而这样的方案就会不同于常见的单一数据实例的方案,这就要程序在运行时根据当时 ...
- nginx动态配置及服务发现那些事
Reference: http://xiaorui.cc/2016/10/16/nginx%E5%8A%A8%E6%80%81%E9%85%8D%E7%BD%AE%E5%8F%8A%E6%9C%8D% ...
- ZooKeeper动态配置(十四)
概述 在3.5.0发行之前,ZK的全体成员和所有其它的配置参数是静态加载的在启动的时候并且在运行的时候不可变.操作员诉诸于"滚动重启" - 一个手动密集和改变配置文件容易出错的方法 ...
- log4net日记文件路径动态配置
在项目开发过程中,部署的服务器越来越多,查看日记的时候需要每台服务器去找日记看,这对运维人员来说是一个很不友好的方式.在此基础上就提出将所有日记统一到一台服务器上进行存放,并按照产生日记的服务器分文件 ...
- .NET Core的响应式框架,基于Ace Admin框架菜单导航,Bootstrap布局,fontAwesome图标,内嵌Iframe用EasyUI做数据绑定,动态配置列表,动态配置表单
netnrf 响应式框架 用于快速开发的响应式框架 演示:https://rf2.netnr.com v3.x 前端采用 jQuery + Bootstrap + EasyUI + AceAdmin ...
- hystrix(一) 简单使用, 以及动态配置更新
本文转载自https://my.oschina.net/u/1169457/blog/1787414 hystrix 简单使用, 以及动态配置更新 概述 只介绍同步模式下简单的使用, 有助于快速接入, ...
- Hyperledger Fabric动态配置Raft节点
Hyperledger Fabric动态配置Raft节点 最近看官方文档发现新的共识算法etcdRaft允许动态添加或删除排序节点,所以也花了一天时间操作了以下,写篇文章把整个过程记录一下. 初始网络 ...
- Kafka动态配置实现原理解析
问题导读 Apache Kafka在全球各个领域各大公司获得广泛使用,得益于它强大的功能和不断完善的生态.其中Kafka动态配置是一个比较高频好用的功能,下面我们就来一探究竟. 动态配置是如何设计的? ...
- 使用 AgileConfig 动态配置 NLog
NLog 是我们在 .NET 领域使用非常广泛的日志组件.它默认使用 xml 来维护它的配置.最近有几个同学问我当使用 AgileConfig 的时候如何配置 NLog .因为 AgileConfig ...
随机推荐
- 为什么Docker比虚拟机快?
1.Docker有着比虚拟机更少的抽象层,由于Docker不需要Hypervisor实现硬件资源虚拟化,运行在Docker容器上的程序直接使用的都是实际物理机的硬件资源,因此在Cpu.内存利用率上Do ...
- Jade教程
Jade 是一个高性能的模板引擎,它深受 Haml 影响,它是用 JavaScript 实现的,并且可以供 Node 使用. 如何在jade模板上加业务逻辑 if res.length==5 h1= ...
- CSS如何进行图文并茂布局怎么破
上下结构 左右结构 右边左边的结构
- 关于python中的module
python中的module(模块),关于这个概念以及使用时主要有以下几点需要注意: (1)import xx时,会首先将这个xx module中的代码执行一遍(且仅执行一遍): 例如: (2)模块包 ...
- UML和模式应用5:细化阶段(8)---逻辑架构和UML包图
1.前言 本章是从面向分析的工作过度到软件设计 典型的OO系统设计的基础是若干架构层,如UI层.应用逻辑(领域)层 本章简要考察逻辑分层架构和相关UML表示法 2.逻辑架构和层 逻辑架构 逻辑架构是软 ...
- 如何提交内核补丁--checkpatch.pl使用【转】
转自:https://blog.csdn.net/qq_29350001/article/details/52056667 转自: http://blog.csdn.net/ganggexiongqi ...
- Win10 + VS2017 15.5.6 环境下解决 Python 3.6 环境无法刷新DB的问题
作为宇宙第一IDE,VS2017对Python的支持还算可以,虽然和PyCharm等Python专用IDE相比还有些差距,但是经过后续的更新升级,我相信VS2017将越来越完善.由于本人一直都是使用V ...
- saltstack自动化运维系列⑦SaltStack实践配置管理安装zabbix
saltstack自动化运维系列⑥SaltStack实践配置管理安装zabbix 1.添加管理zabbix的sls文件# vim /srv/salt/base/init/zabbix_agent.sl ...
- Ex 5_21 无向图G=(V,E)的反馈边集..._第九次作业
根据题意,求的是最大生成树.利用Kruskal算法,对边进行从大到小的顺序进行排序,然后再依次取出边加入结果集中.假设图有n个顶点,那么,当结果集中有n-1条边时,剩下的边的集合即为反馈边集. pac ...
- WebMvcConfigurerAdapter已过时
Spring Boot2.0的版本(创建的时候自动选择的这个版本),然后编译器告诉我WebMvcConfigurerAdapter已过时了 @Deprecated public abstract cl ...