.Net6 微服务之Ocelot+IdentityServer4入门看这篇就够了
前言
.Net 6 使用 Consul 实现服务注册与发现 看这篇就够了
.Net6 使用 Ocelot + Consul 看这篇就够了
.Net6 微服务之Polly入门看这篇就够了
书接上文,本文将继续建立在 .Net6 使用 Ocelot + Consul 看这篇就够了文章中的项目基础上来进行Ocelot与IdentityServer4的介绍。项目也都比较简单,不熟悉的同学可以去翻翻我之前的文章,相信都能一看就会。其实网上关于Id4的文章还是比较多了,本文只会对其进行简单的介绍,不会过多深究,感兴趣的同学可以自行研究。然后本文只是个人学习与分享,不喜勿喷,谢谢!
什么是IdentityServer4?
IdentityServer 是一个 OpenID Connect 提供者—— 它实现了 OpenID Connect 和 OAuth 2.0 协议。
- User:用户
- Client:客户端
- Resources:Identity Data(身份数据)、Apis
- Identity Server:认证授权服务器
- Token:Access Token(访问令牌)和 Identity Token(身份令牌)
基于以上我们先来简单了解 OAuth2.0 与 OpenID Connect是个什么东西,它们能干些什么?解决了哪些问题以及我们怎么使用它们?我们需要带着一些问题来学习新东西才会事半功倍。
OAuth2
OAuth是一个开放授权标准,是一个授权协议,并不是认证协议,它无法提供完善的身份认证功能,它解决的问题是授权 。本文介绍的版本为2.0。
它允许用户让第三方应用访问该用户在某服务的特定私有资源,但是不提供账号密码给第三方用户。然后它是通过给用户提供Token(令牌)的方式来访问他们存放在特定服务商上的数据,每一个Token授权一个特定的网站内访问特定的资源,而不是一味的放开所有内容。
下面是OAuth 2.0的运行流程图以及相关介绍:
Client:客户端
Resource Owner:资源所有者
Authorization Server:认证服务器,即服务提供商专门用来处理认证的服务器。
Resource Server:资源服务器,即服务提供商存放用户生成的资源的服务器。它与认证服务器,可以是同一台服务器,也可以是不同的服务器。
(A)用户打开客户端以后,客户端要求用户给予授权。
(B)用户同意给予客户端授权。
(C)客户端使用上一步获得的授权,向认证服务器申请令牌。
(D)认证服务器对客户端进行认证以后,确认无误,同意发放令牌。
(E)客户端使用令牌,向资源服务器申请获取资源。
(F)资源服务器确认令牌无误,同意向客户端开放资源。
简单了解之后,我们可以发现B步骤是关键,即用户怎么才能给客户端授权。只有拿到这个授权之后,客户端才能获取到令牌,从而凭借令牌获取资源。所以OAuth2.0为此定义了四种授权方式,如下:
- 授权码模式(authorization code)
- 简化模式(implicit)
- 密码模式(resource owner password credentials)
- 客户端模式(client credentials)
这里我们只做简单了解,就不展开了,感兴趣的同学可以参考官网或者大佬的文章。
OpenId Connect(OIDC)
OpenId Connect = OIDC = Authentication + Authorization + OAuth2.0
OIDC是一个基于OAuth2协议的身份认证标准协议,解决的问题是用户认证,而不关心授权。
我们都知道OAuth2是一个授权协议,它无法提供完善的身份认证功能,所以OIDC干的活就是使用OAuth2的授权服务器来为第三方客户端提供用户的身份认证,并把对应的身份认证信息传递给客户端,且可以适用于各种类型的客户端(比如服务端应用,移动APP,JS应用),且完全兼容OAuth2,也就是说你搭建了一个OIDC的服务后,也可以当作一个OAuth2的服务来用。
下面是OIDC的运行流程图以及相关介绍:
- EU:End User:一个人类用户。
- RP:Relying Party ,用来代指OAuth2中的受信任的客户端,身份认证和授权信息的消费方;
- OP:OpenID Provider,有能力提供EU认证的服务(比如OAuth2中的授权服务),用来为RP提供EU的身份认证信息;
- ID Token:JWT格式的数据,包含EU身份认证的信息。
- UserInfo Endpoint:用户信息接口(受OAuth2保护),当RP使用Access Token访问时,返回授权用户的信息,此接口必须使用HTTPS。
- AuthN:Authentication 认证
- AuthZ:Authorization 授权
- RP发送一个认证请求给OP;
- OP对EU进行身份认证,然后提供授权;
- OP把ID Token和Access Token(需要的话)返回给RP;
- RP使用Access Token发送一个请求UserInfo EndPoint;
- UserInfo EndPoint返回EU的Claims。
注意这里面RP发往OP的请求,是属于Authentication类型的请求,虽然在OIDC中是复用OAuth2的Authorization请求通道,但是用途是不一样的,且OIDC的AuthN请求中scope参数必须要有一个值为的openid的参数,用来区分这是一个OIDC的Authentication请求,而不是OAuth2的Authorization请求。
然后我们简单了解下 ID Token
ID Token
OIDC对OAuth2最主要的扩展就是提供了ID Token.
ID Token是一个安全令牌,是一个授权服务器提供的包含用户信息(由一组Cliams构成以及其他辅助的Cliams)的JWT格式的数据结构。
ID Token的主要构成部分如下(使用OAuth2流程的OIDC)。
- iss = Issuer Identifier:必须。提供认证信息者的唯一标识。一般是一个https的url(不包含querystring和fragment部分)。
- sub = Subject Identifier:必须。iss提供的EU的标识,在iss范围内唯一。它会被RP用来标识唯一的用户。最长为255个ASCII个字符。
- aud = Audience(s):必须。标识ID Token的受众。必须包含OAuth2的client_id。
- exp = Expiration time:必须。过期时间,超过此时间的ID Token会作废不再被验证通过。
- iat = Issued At Time:必须。JWT的构建的时间。
- auth_time = AuthenticationTime:EU完成认证的时间。如果RP发送AuthN请求的时候携带max_age的参数,则此Claim是必须的。
- nonce:RP发送请求的时候提供的随机字符串,用来减缓重放攻击,也可以来关联ID Token和RP本身的Session信息。
- acr = Authentication Context Class Reference:可选。表示一个认证上下文引用值,可以用来标识认证上下文类。
- amr = Authentication Methods References:可选。表示一组认证方法。
- azp = Authorized party:可选。结合aud使用。只有在被认证的一方和受众(aud)不一致时才使用此值,一般情况下很少使用。
这里只是简单介绍,感兴趣的同学可以去官网了解更多。下面开始实操。
抛玉引砖 O(∩_∩)O !
项目准备
.Net 6
Visual Studio 2022
https://github.com/fengzhonghao8-24/Consul.Ocelot
搭建IdentityServer4项目
我们基于上篇项目来新增一个IdentityServer4Center项目
引入IdentityServer4 Nuget包,然后新增一个配置文件 Config.cs 配置模拟数据
定义API范围
//https://www.cnblogs.com/Mamba8-24
public static IEnumerable<ApiScope> ApiScopes =>
new List<ApiScope>
{
new ApiScope("serviceA"),
new ApiScope("serviceB")
};
定义API资源
//https://www.cnblogs.com/Mamba8-24
public static IEnumerable<ApiResource> GetApiResources()
{
return new List<ApiResource>()
{
new ApiResource("serviceA","serviceA"){ Scopes={ "serviceA" } },
new ApiResource("serviceB","serviceB"){ Scopes={ "serviceB" } }
};
}
定义客户端
//https://www.cnblogs.com/Mamba8-24
public static IEnumerable<Client> GetClients()
{
return new List<Client>
{
new Client{
ClientId="web_client",//客户端唯一标识
ClientName="AuthCenter",
//AllowedGrantTypes=new List<string>{ "paas_password", "paas_auth_code", "client_credentials"},
AllowedGrantTypes=GrantTypes.ClientCredentials,
ClientSecrets=new[]{new Secret("Mamba24".Sha256()) },//客户端密码,进行了加密
AccessTokenLifetime=3600,
AllowedScopes=new List<string>//允许访问的资源
{
"serviceA",
"serviceB"
},
Claims=new List<ClientClaim>(){
new ClientClaim(IdentityModel.JwtClaimTypes.Role,"Admin"),
new ClientClaim(IdentityModel.JwtClaimTypes.NickName,"Mamba24"),
}
}
};
}
然后在Program.cs进行DI
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddInMemoryClients(Config.GetClients())//Client模式
.AddInMemoryApiScopes(Config.ApiScopes)//作用域
.AddInMemoryApiResources(Config.GetApiResources());//资源
var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();
app.UseIdentityServer();//使用Id4
然后我们将项目run起来看看效果:
使用Postman请求Token
这里请求参数内容都是在定义客户端的时候定义好的,只需要注意 grant_type 这里为 client_credentials 客户端模式,如果在定义客户端的时候AllowedGrantTypes 配置的是 ResourceOwnerPassword 则 grant_type 为 password,具体参考GrantTypes.cs。
OK,IdentityServer4Center项目搭建完成。接下来我们将网关与 IdentityServer4 结合使用。
Ocelot结合dentityServer4
接下来会模拟通过集成了Id4的网关来访问ServiceA或者ServiceB服务以达到演示效果。
首先我们在Gateway项目中装两个包
然后在ocelot.json 文件中增加Id4鉴权资源
{
"Routes": [
{
"DownstreamPathTemplate": "/{url}", //下游(转发的服务地址模板)
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 5550
}
],
"UpstreamPathTemplate": "/ocelot/{url}", //上游(请求路径模板)
"UpstreamHttpMethod": [ "Get", "Post" ],
//鉴权
"AuthenticationOptions": {
"AuthenticationProviderKey": "serviceA", //指定一个key
"AllowedScopes": [ "serviceA" ] //id4的作用域名称
}
},
{
"DownstreamPathTemplate": "/{url}", //下游(转发的服务地址模板)
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 5551
}
],
"UpstreamPathTemplate": "/ocelotB/{url}", //上游(请求路径模板)
"UpstreamHttpMethod": [ "Get", "Post" ],
//鉴权
"AuthenticationOptions": {
"AuthenticationProviderKey": "serviceB", //指定一个key
"AllowedScopes": [ "serviceB" ] //id4的作用域名称
}
}
]
}
然后在 Program.cs进行配置
由于Ocelot网关默认集成了Id4所以我们只需要在之前代码的基础上增加对需要进行鉴权服务的配置。
var builder = WebApplication.CreateBuilder(args);
builder.Configuration.AddJsonFile("ocelot.json", optional: false, reloadOnChange: true);
var authenticationProviderKey = "serviceA";
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddIdentityServerAuthentication(authenticationProviderKey, options =>
{
options.Authority = "http://localhost:5269";//id4服务地址
options.ApiName = "serviceA";//id4 api资源里的apiname
options.RequireHttpsMetadata = false; //不使用https
options.SupportedTokens = SupportedTokens.Both;
});
authenticationProviderKey = "serviceB";
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddIdentityServerAuthentication(authenticationProviderKey, options =>
{
options.Authority = "http://localhost:5269";//id4服务地址
options.ApiName = "serviceB";//id4 api资源里的apiname
options.RequireHttpsMetadata = false; //不使用https
options.SupportedTokens = SupportedTokens.Both;
});
builder.Services.AddOcelot().AddConsul();
到这里我们就差不多简单的配置完成了,接下来看看效果。
同时启动Gateway,IdentityServer4Center,ServiceA,ServiceB项目
网关项目启动地址端口为5055
我们现在直接通过网关来请求ServiceA服务的接口(不带token) http://localhost:5055/ocelot/testA
结果出现401,达到预期效果
接着我们带上token再次访问
返回200,请求成功。
然后接下来我们给ServiceB 服务单独增加授权认证,模拟请求绕过网关直接访问下游服务。
Program.cs
代码很简单,我们单独访问ServiceB看看效果
结果出现 401
然后我们拿着token去访问
可以正常访问
到此,我们基于 客户端模式(client credentials)模拟的一个简单的示例就完成了,这个模式没有用户参与,也就是说此模式只适用于在资源或者资源服务器不属于某个人或者用户,没有资源所有者对资源进行控制,但是客户端需要访问这个受保护资源的情况下。
接下来我们可以尝试在客户端模式(client credentials)下访问Id4的身份认证资源(对应用户)
我们稍微调整代码
Config.cs
模拟用户
Program.cs
然后我们先在 client credentials 客户端模式 下请求token,去访问Id4的身份认证资源。
出现 403异常,所以在这个模式下这样的请求是不合理的,这也就验证了我们上述所说。
接下来我们可以尝试模拟 密码模式(resource owner password credentials)这个模式会有用户参与
然后再次访问Id4的身份认证资源
OK,成功拿到资源信息。
结尾
由于文章篇幅有限,涉及到知识内容也不是很深入,感兴趣的同学可以自行研究。
然后本文都是基于我的个人理解,然后也有参考官网以及大佬的文章和视频,文章如有什么不妥的地方欢迎指正,共同进步。后续有时间还会继续学习相关技术知识,欢迎Star与关注。谢谢!
参考链接
https://www.bilibili.com/video/BV16b411k7yM?p=5
https://identityserver4docs.readthedocs.io/zh_CN/latest/index.html
https://www.cnblogs.com/linianhui/category/929878.html
源码地址
https://github.com/fengzhonghao8-24/Consul.Ocelot.IdentityServer4.git
.Net6 微服务之Ocelot+IdentityServer4入门看这篇就够了的更多相关文章
- React入门看这篇就够了
摘要: 很多值得了解的细节. 原文:React入门看这篇就够了 作者:Random Fundebug经授权转载,版权归原作者所有. React 背景介绍 React 入门实例教程 React 起源于 ...
- [转帖]Zookeeper入门看这篇就够了
Zookeeper入门看这篇就够了 https://my.oschina.net/u/3796575/blog/1845035 Zookeeper是什么 官方文档上这么解释zookeeper,它是一个 ...
- [转]React入门看这篇就够了
摘要: 很多值得了解的细节. 原文:React入门看这篇就够了 作者:Random Fundebug经授权转载,版权归原作者所有. React 背景介绍 React 入门实例教程 React 起源于 ...
- .Net6 微服务之Polly入门看这篇就够了
前言 O(∩_∩)O 大家好!书接上文,本文将会继续建立在 .Net6 使用 Ocelot + Consul 看这篇就够了 项目的基础上进行Polly的介绍,然后这篇文章只是个人学习与分享,不喜勿喷, ...
- .NET Core实战项目之CMS 第五章 入门篇-Dapper的快速入门看这篇就够了
写在前面 上篇文章我们讲了如在在实际项目开发中使用Git来进行代码的版本控制,当然介绍的都是比较常用的功能.今天我再带着大家一起熟悉下一个ORM框架Dapper,实例代码的演示编写完成后我会通过Git ...
- ZooKeeper 入门看这篇就够了
什么是 ZooKeeper? ZooKeeper 是一个分布式的,开放源码的分布式应用程序协同服务.ZooKeeper 的设计目标是将那些复杂且容易出错的分布式一致性服务封装起来,构成一个高效可靠的原 ...
- Zookeeper入门看这篇就够了!!
Zookeeper是什么 官方文档上这么解释zookeeper,它是一个分布式服务框架,是Apache Hadoop 的一个子项目,它主要是用来解决分布式应用中经常遇到的一些数据管理问题,如:统一命名 ...
- EFCore 6.0入门看这篇就够了
前言 作为一直在dotNet行业耕耘的码农,这几年在大大小小项目中也涉及到了许多ORM框架,比如:EFCore,Dapper,NHibernate,SqlSugar等等,这些ORM都有各自的优缺点,大 ...
- Storm入门,看这篇就够了
部分一:Srorm 简介 1.1 Storm是实时的数据流,Hadoop是批量离线数据 起源背景 Twitter 开源的一个类似于Hadoop的实时数据处理框架 Storm是由Nathan Marz ...
- Zookeeper入门看这篇就够了
https://blog.csdn.net/java_66666/article/details/81015302
随机推荐
- nginx配置文件讲解及示例(可复制)
详细的配置说明参考:https://www.cnblogs.com/ghl1024/p/9013805.html [示例一] #运行用户user www-data; #启动进程,通常设置成和cpu ...
- 【每日一题】【dfs重载原始函数&循环/函数结束条件&左右下标在数组中位置的确定】2022年2月7日-NC12 由先序和中序遍历重建二叉树
描述给定节点数为 n 的二叉树的前序遍历和中序遍历结果,请重建出该二叉树并返回它的头结点.例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建 ...
- 【每日一题】【遍历orSet】2022年2月1日-NC66 两个链表的第一个公共结点
描述输入两个无环的单向链表,找出它们的第一个公共结点,如果没有公共节点则返回空.(注意因为传入数据是链表,所以错误测试数据的提示是用其他方式显示的,保证传入数据是正确的) 输入描述:输入分为是3段,第 ...
- form表单里的button 等元素不能使用margin: 0 auto;
记得把form和button都设为display:block; 就能用margin: 0 auto;水平居中了
- Pytorch框架详解之一
Pytorch基础操作 numpy基础操作 定义数组(一维与多维) 寻找最大值 维度上升与维度下降 数组计算 矩阵reshape 矩阵维度转换 代码实现 import numpy as np a = ...
- 开发一个MyBatis通用Mapper的轮子
一.前言 程序猿为什么如此执着于造轮子?MyBatis-Plus如此强大的工具流行这么多年了,我为啥还在重复造这样的轮子? 1.公司的技术规范不允许使用MyBatis-Plus,咱也不知道什么原因: ...
- 有关WCH的CH42x以及CH45x选型,常见问题处理方法
南京沁恒微电子的CH45x系列为数码管.按键驱动芯片. CH42x系列为IO扩展芯片.CH422和CH423除了支持的OC数量有一些区别,在单片机的驱动上,并没有任何区别,驱动CH423的代码是可以套 ...
- gitee删除上传到的远程分支的提交记录
在实际开发中可能也经常会遇到写完代码后提交到远程分支但发现写的提交信息有误,不符合规范.由于自己的gitee账号可能没有修改提交记录的权限.因此最佳的解决方法是,撤销本地分支当前的提交记录,将代码回滚 ...
- [编程基础] C++多线程入门8-从线程返回值
原始C++标准仅支持单线程编程.新的C++标准(称为C++11或C++0x)于2011年发布.在C++11中,引入了新的线程库.因此运行本文程序需要C++至少符合C++11标准. 8 从线程返回值 8 ...
- Java基础篇——垃圾收集详解
JAVA垃圾收集 1.如何判断对象死亡 说道垃圾回收,那么首要问题就是jvm如何判断一个对象已经死亡呢 1.1 引用计数法 说白了,就是为每个对象设立一个引用计数器,每当有一个引用指向它,计数器加一, ...