项目搭建肯定少不了认证和授权,传统的单体应用基于cookie和session来完成的。

因为http请求是无状态的,每个请求都是完全独立的,服务端无法确认当前请求之前是否登陆过。所以第一次请求(登录),服务器会返回SessionID 返回给浏览器,浏览器会存于Cookie中,下次请求带上SessionID.这样服务端每次拿到SessionID后就去找是否存在对应的会话信息,判断过期及后续操作等......

这个授权操作适用于MVC的项目,在分布式的项目中就不行了。session信息存在不同的服务实例中,在集群应用中一般都采取轮询机制,A服务实例保存了session信息,B服务实例上没有这个信息,请求达到B服务是会返回401的code信息,但是已经登录过,所以问题就暴露了......

针对此问题,可采取Session共享:将session信息存入redis中,每个服务实例都从redis中拿session信息。 会话粘滞:这个可以依靠nginx实现,也就是请求从登录开始,每个请求都会访问同一个服务实例。第一次登录访问的服务实例,之后每一次都会访问这个服务实例。但是这个就脱离了负载均衡策略,用可能100个请求,80个都是A服务接收......

OAuth2.0(协议)

数据所有者告诉系统,同意授权第三方应用进入系统,获取这些数据。系统从而产生一个短期的进入令牌,用来代替密码,供第三方应用使用。

规范了下授权的流程,五种模式:

客户端凭证(client credentials)
密码式(password)
隐藏式(implicit)
授权码(authorization-code)
混合式(Hybrid)

IdentityServer4

IdentityServer4(认证授权的中间件)是在.Net Core微服务架构中首选的授权认证解决方案。为Asp.Net Core量身定制实现了OpenId Connect和OAuth2.0协议(规范)。

使用IdentityServer4构建鉴权中心

引入NuGet包:IdentityServer4

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseIdentityServer();//添加认证中间件 app.UseHttpsRedirection(); app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers(); //客户端模式--怎么执行Ids4
services.AddIdentityServer()//怎么处理
.AddDeveloperSigningCredential()//默认开发者证书,每一次启动证书都会刷新
.AddInMemoryClients(InitConfig.GetClients())//InMemory 内存模式
.AddInMemoryApiResources(InitConfig.GetApiResources());//能访问啥资源
}
/// <summary>
/// 自定义管理信息
/// </summary>
public class InitConfig
{
/// <summary>
/// 定义ApiResource
/// 这里的资源(Resource)指的就是管理的Api
/// </summary>
/// <returns></returns>
public static IEnumerable<ApiResource> GetApiResources()
{
return new[]
{
new ApiResource("UserApi","用户获取Api")
};
} /// <summary>
/// 定义验证条件的Client
/// </summary>
/// <returns></returns>
public static IEnumerable<Client> GetClients()
{
return new[]
{
new Client
{
ClientId="authentication",//客户端唯一标识
ClientSecrets=new[]{new Secret("auth123456".Sha256()) },//客户端密码进行加密
//AllowedGrantTypes=GrantType.ClientCredentials,//验证模式
AllowedGrantTypes={GrantType.ClientCredentials },//验证模式
AllowedScopes=new []{ "UserApi"},//作用域,可以访问的资源,该用户可访问哪些Api
Claims=new List<Claim>()
{
new Claim(IdentityModel.JwtClaimTypes.Role,"admin"),
new Claim(IdentityModel.JwtClaimTypes.NickName,"江北"),
new Claim("Email","**********@163.com"),
}
}
};
}
}

使用Postman测试:

在服务实例中加入鉴权中间件,引入NuGet包 IdentityServer4.AccessTokenValidation,并在需要鉴权的接口上面标识[Authorize]特性

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
} app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
}); app.UseHttpsRedirection(); app.UseRouting(); app.UseAuthentication();//鉴权,没有鉴权,授权是没有意义的
app.UseAuthorization();//授权 app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
}); //启动时注册,且注册一次
this.Configuration.ConsulExtend();
}
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication("Bearer")
.AddIdentityServerAuthentication(m =>
{
m.Authority = "http://localhost:7200";//Ids的地址
m.ApiName = "GetCustomerUser";
m.RequireHttpsMetadata = false;
});
}

直接访问会报401的错误

先去请求鉴权中心,拿到Token后,带上Token请求

如果报下面这个错误,可能是作用域的问题,你请求的Api和可访问的Api集合对不上

针对上面的过程,我们理一理流程。首先我们在A鉴权服务中心请求获取Token,拿到Token后去请求B实例服务上的接口。A鉴权中心和B服务实例并没有进行交互,B服务实例怎样识别Token,这之间是怎样的验证的呢?

其实这里有一个加密算法

非对称可逆加密,加密Key和解密Key不同(一对儿),而且无法推导
加密--content--result(原文加密为密文)
解密--result--content(通过密文解密为原文) 公开解密key-公钥
私藏加密key-私钥

再来走一下流程,首先在A鉴权中心验证登录,并将获取的用户信息用私钥加密作为Token进行响应返回。所以在Token中不适合存一些敏感信息。但是有一点可以保证,只要是用这个私钥配对的公钥解开的Token,那么一定是由这个私钥加密的,就证明这个Token是合法的,可通过的。

那什么时候拿到公钥?第一次.没错,在第一次请求到达B服务实例的时候,B服务实例会去A鉴权中心请求拿到公钥。之后就不在需要和A鉴权中心进行交互,除非B服务实例重新启动。

既然是微服务架构,所以鉴权也统一走网关,不然每一个服务实例都要写一套鉴权的代码。因为走网关鉴权,所以所有的api都要授权才能访问。

在网关服务中引入包 IdentityServer4.AccessTokenValidation

public void ConfigureServices(IServiceCollection services)
{
#region Identity4
var authenticationProviderKey = "Gatewaykey";
services.AddAuthentication("Bearer")
.AddIdentityServerAuthentication(authenticationProviderKey, m =>
{
m.Authority = "http://localhost:7200";//Ids的地址,获取公钥
m.ApiName = "GetCustomerUser";
m.RequireHttpsMetadata = false;
m.SupportedTokens = SupportedTokens.Both;
});
#endregion
}
//*************************Consul+Cache+超时+限流+熔断+降级*****************************
"Routes": [
{
//GeteWay转发=>Downstream
"DownstreamPathTemplate": "/api/{url}", //服务地址--url变量
"DownstreamScheme": "http",
//http://localhost:6299/T5/User/GetCustomerUser
"UpstreamPathTemplate": "/T5/{url}", //网关地址--url变量 冲突的还可以加权重Priority
"UpstreamHttpMethod": [ "Get", "Post" ],
"UseServiceDiscovery": true, //使用服务发现
"ServiceName": "MicroserviceAttempt", //Consul服务名称
"LoadBalancerOptions": {
"Type": "RoundRobin" //轮询 //"LeastConnection":最少连接数服务器 "NoloadBalance":不负载均衡 "CookieStickySession":会话粘滞
},
//使用缓存
"FileCacheOptions": {
"TtlSeconds": , //过期时间
"Region": "UserCache" //可以调用Api清理
},
//限流 张队长贡献的
"RateLimitOptions": {
"ClientWhitelist": [ "Microservice", "Attempt" ], //白名单 ClientId区分大小写
"EnableRateLimiting": true,
"Period": "1s", //5m 1h 1d
"PeriodTimespan": , //多少秒之后客户端可以重试
"Limit": //统计时间段内允许的最大请求数
},
//鉴权
"AuthenticationOptions": {
"AuthenticationProviderKey": "Gatewaykey",
"AllowedScopes": []
},
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": , //熔断之前允许多少个异常请求
"DurationOfBreak": , //熔断的时间,单位为ms.超过这个时间可再请求
"TimeoutValue": //如果下游请求的处理时间超过多少则将请求设置为超时 默认90秒
}
}
],
"GlobalConfiguration": {
"BaseUrl": "http://127.0.0.1:6299",
"ServiceDiscoveryProvider": {
"Host": "localhost",
"Port": ,
"Type": "Consul" //由Consul提供服务发现,每次请求去Consul
},
"RateLimitOptions": {
"QuotaExceededMessage": "Customize Tips!", //限流时返回的消息
"HttpStatusCode": //限流时返回的code
}
//"ServiceDiscoveryProvider": {
// "Host": "localhost",
// "Port": 8500,
// "Type": "PollConsul", //由Consul提供服务发现,每次请求去Consul
// "PollingInterval": 1000//轮询Consul,评率毫秒--down是不知道的
//}
}
//*************************Consul+Cache+超时+限流+熔断+降级*****************************

启动鉴权服务、网关、服务实例

Postman测试

当然,还不是很完善,还要加策略授权模式。后期我会再补充

如有不当,望包涵!

微服务项目整合Ocelot+IdentityServer4的更多相关文章

  1. .Net Core 商城微服务项目系列(一):使用IdentityServer4构建基础登录验证

    这里第一次搭建,所以IdentityServer端比较简单,后期再进行完善. 1.新建API项目MI.Service.Identity,NuGet引用IdentityServer4,添加类InMemo ...

  2. .NET Core 微服务—API网关(Ocelot) 教程 [三]

    前言: 前一篇文章<.NET Core 微服务—API网关(Ocelot) 教程 [二]>已经让Ocelot和目录api(Api.Catalog).订单api(Api.Ordering)通 ...

  3. .NET Core微服务之基于Ocelot实现API网关服务

    Tip: 此篇已加入.NET Core微服务基础系列文章索引 一.啥是API网关? API 网关一般放到微服务的最前端,并且要让API 网关变成由应用所发起的每个请求的入口.这样就可以明显的简化客户端 ...

  4. .NET Core微服务二:Ocelot API网关

    .NET Core微服务一:Consul服务中心 .NET Core微服务二:Ocelot API网关 .NET Core微服务三:polly熔断与降级 本文的项目代码,在文章结尾处可以下载. 本文使 ...

  5. .NET Core 微服务—API网关(Ocelot) 教程 [二]

    上篇文章(.NET Core 微服务—API网关(Ocelot) 教程 [一])介绍了Ocelot 的相关介绍. 接下来就一起来看如何使用,让它运行起来. 环境准备 为了验证Ocelot 网关效果,我 ...

  6. SpringCloud(1)---基于RestTemplate微服务项目案例

    基于RestTemplate微服务项目 在写SpringCloud搭建微服务之前,我想先搭建一个不通过springcloud只通过SpringBoot和Mybatis进行模块之间额通讯.然后在此基础上 ...

  7. Docker部署golang微服务项目

    这篇博客是为了记录一下部署步骤. 因为实训需要,我要在服务器上用docker部署我们小组的微服务项目.我们的微服务有Gateway,User,Scene,Device四个部分,分别占用不同的端口,其中 ...

  8. docker微服务部署之:三,搭建Zuul微服务项目

    docker微服务部署之:二.搭建文章微服务项目 一.新增demo_eureka模块,并编写代码 右键demo_parent->new->Module->Maven,选择Module ...

  9. docker微服务部署之:二、搭建文章微服务项目

    docker微服务部署之:一,搭建Eureka微服务项目 一.新增demo_article模块,并编写代码 右键demo_parent->new->Module->Maven,选择M ...

随机推荐

  1. windows 下安装YApi及集成Idea的YapiUpload

    一准备工具 Mongodb Node和npm 二文档地址 https://hellosean1025.github.io/yapi/ 三安装步骤 1.安装Mongodb,请参考 2.安装Node,请参 ...

  2. 深入理解Spring AOP 1.0

    本文相关代码(来自官方源码spring-test模块)请参见spring-demysify org.springframework.mylearntest包下. 统称能够实现AOP的语言为AOL,即( ...

  3. Python随机数函数

    Python随机数函数: ''' choice(seq) 从序列的元素中随机选出一个元素 randrange ([start,] stop [,step]) 从指定范围内,在指定步长递增的集合中 获取 ...

  4. Django学习路19_is_delete属性,重写类方法,显性隐性属性

    如果在 创建数据表时,使用了 objects = models.Model() 使隐形属性变为了 显性属性 则 必须要自己定义一个 继承了 models.Model 类的类,实现 管理功能 如果一个属 ...

  5. Seaborn基础1

    import seaborn as sns import numpy as np import matplotlib.pyplot as plt # # 折线图 def sinplot(flip = ...

  6. Python file() 函数

    描述 file() 函数用于创建一个 file 对象,它有一个别名叫 open(),更形象一些,它们是内置函数.参数是以字符串的形式传递的.每组词 www.cgewang.com 更多文件操作可参考: ...

  7. PHP tmpfile() 函数

    定义和用法 tmpfile() 函数以读写(w+)模式创建一个具有唯一文件名的临时文件. 语法 tmpfile() 提示和注释 注释:临时文件会在文件关闭后(用 fclose())或当脚本结束后自动被 ...

  8. ZROI 提高十连测 DAY2

    总结:入题尽量快,想到做法要先证明是否正确是否有不合法的情况,是否和题目中描述的情景一模一样.    不要慌 反正慌也拿不了多少分,多分析题目的性质如果不把题目的性质分析出来的话,暴力也非常的难写,有 ...

  9. linux的文件处理(匹配 正则表达式 egrep awk sed)和系统、核心数据备份

    文件处理 1.处理方式 匹配 正则表达式 egrep awk sed 2.文件中的处理字符 \n  新行符 换行 \t  制表符 tab键 缺省8个空格 \b  退格符 backspace键 退格键 ...

  10. 使用VMware虚拟机建立Ubuntu与主机win7的文件共享与传输

    1.要想在虚拟机与主机之间建立共享文件夹必须先安装VMware Tools.方法见https://www.cnblogs.com/lsc666js/p/13403919.html. 2.在VMware ...