NET Core + Ocelot + IdentityServer4 + Consul
.NET Core + Ocelot + IdentityServer4 + Consul 基础架构实现
先决条件
- 关于 Ocelot
- 针对使用 .NET 开发微服务架构或者面向服务架构提供一个统一访问系统的组件。 参考
- 本文将使用 Ocelot 构建统一入口的 Gateway。
- 关于 IdentityServer4
- IdentityServer4 是一个 OpenID Connect 和 OAuth 2.0 框架用于 ASP.NET Core 。IdentityServer4 在你的应用程序中集成了基于令牌认证、单点登录、API访问控制所需的所有协议和扩展点。参考
- 本文将使用 IdentityServer4 搭建独立认证服务器。
- 关于 Consul
- Consul 是一个服务网格解决方案,通过服务发现、配置、功能分割提供一个全功能的控制层。这些功能可以单独使用,也可以同时使用以形成一个完整的网格服务。参考
- 本文将使用 Consul 注册多个服务。
- 关于 .Net Core
- 将使用 WebApi 构建多个服务
构建 IdentityServer 服务
- 添加 ASP.Net Core Web 项目

- 添加空项目

- 在程序包管理控制台中输入:Install-Package IdentityServer4.AspNetIdentity
添加 Config.cs 文件,并添加内容如下:
using System.Collections.Generic;
using IdentityServer4.Models;
using IdentityServer4.Test; namespace IdentityServer
{
public sealed class Config
{
public static IEnumerable<ApiResource> GetApiResources()
{
return new List<ApiResource>
{
new ApiResource("ServiceA", "ServiceA API"),
new ApiResource("ServiceB", "ServiceB API")
};
} public static IEnumerable<Client> GetClients()
{
return new List<Client>
{
new Client
{
ClientId = "ServiceAClient",
AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
ClientSecrets =
{
new Secret("ServiceAClient".Sha256())
},
AllowedScopes = new List<string> {"ServiceA"},
AccessTokenLifetime = 60 * 60 * 1
},
new Client
{
ClientId = "ServiceBClient",
AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
ClientSecrets =
{
new Secret("ServiceBClient".Sha256())
},
AllowedScopes = new List<string> {"ServiceB"},
AccessTokenLifetime = 60 * 60 * 1
}
};
} public static List<TestUser> GetUsers()
{
return new List<TestUser>
{
new TestUser
{
Username = "test",
Password = "123456",
SubjectId = "1"
}
};
} public static IEnumerable<IdentityResource> GetIdentityResources()
{
return new List<IdentityResource>();
}
}
}注意:这里添加了两个 Client ,分别为 ServiceA、ServiceB ,因此接下来将构建这两个服务。
删掉StartUp.cs文件,在Program.cs中添加内容如下:
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection; namespace IdentityServer
{
public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
} public static IWebHostBuilder CreateWebHostBuilder(string[] args)
{
return WebHost.CreateDefaultBuilder(args).ConfigureServices(services =>
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddInMemoryIdentityResources(Config.GetIdentityResources())
.AddInMemoryApiResources(Config.GetApiResources())
.AddInMemoryClients(Config.GetClients())
.AddTestUsers(Config.GetUsers());
}).Configure(app =>
{
app.UseIdentityServer();
});
}
}
}注意:AddDeveloperSigningCredential() 方法用于添加开发时使用的 Key material ,生产环境中不要使用该方法。在 .NET Core 2.2 中新建的 Web 项目文件 csproj 中包含了如下内容:
csharp <PropertyGroup> <TargetFramework>netcoreapp2.2</TargetFramework> <AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel> </PropertyGroup>
这里更改csharp <AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
为或直接删除该行,这么做的原因是当值为 InProcess 时,读写 tempkey.rsa 将产生权限问题。关于 AspNetCoreHostingModel 可参考 ASP.NET Core Module 。csharp <AspNetCoreHostingModel>OutOfProcess</AspNetCoreHostingModel>F5 启动该服务,显示如下:

在浏览器中输入 http://localhost:38033/.well-known/openid-configuration ,得到以下内容

至此,一个包含两个服务认证的认证服务搭建完毕。
构建 ServiceA、ServiceB
添加 ASP.Net Core Web 项目,这里以 ServiceA 为例进行构建

添加 ASP.Net Core API

在 StartUp.cs 中添加内容如下:
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; namespace ServiceA
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
} public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); services.AddAuthentication("Bearer")
.AddJwtBearer("Bearer", options =>
{
options.Authority = "http://127.0.0.1:8021";
options.RequireHttpsMetadata = false;
options.Audience = "ServiceA";
});
} // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseAuthentication();
app.UseMvc();
}
}
}
添加 SessionController 用于用户登录,内容如下:
using System.ComponentModel.DataAnnotations;
using System.Net.Http;
using System.Threading.Tasks;
using IdentityModel.Client;
using Microsoft.AspNetCore.Mvc; namespace ServiceA.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class SessionController : ControllerBase
{
public async Task<string> Login(UserRequestModel userRequestModel)
{
// discover endpoints from metadata
var client = new HttpClient();
DiscoveryResponse disco = await client.GetDiscoveryDocumentAsync("http://127.0.0.1:8021");
if (disco.IsError)
{
return "认证服务器未启动";
}
TokenResponse tokenResponse = await client.RequestPasswordTokenAsync(new PasswordTokenRequest
{
Address = disco.TokenEndpoint,
ClientId = "ServiceAClient",
ClientSecret = "ServiceAClient",
UserName = userRequestModel.Name,
Password = userRequestModel.Password
}); return tokenResponse.IsError ? tokenResponse.Error : tokenResponse.AccessToken;
}
} public class UserRequestModel
{
[Required(ErrorMessage = "用户名称不可以为空")]
public string Name { get; set; } [Required(ErrorMessage = "用户密码不可以为空")]
public string Password { get; set; }
}
}添加 HealthController 用于 Consul 进行服务健康检查,内容如下:
using Microsoft.AspNetCore.Mvc; namespace ServiceA.Controllers
{
[Route("api/[controller]"), ApiController]
public class HealthController : ControllerBase
{
/// <summary>
/// 健康检查
/// </summary>
/// <returns></returns>
[HttpGet]
public IActionResult Get()
{
return Ok();
}
}
}更改 ValuesController.cs 内容如下:
using System.Collections.Generic;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; namespace ServiceA.Controllers
{
[Authorize] //添加 Authorize Attribute 以使该控制器启用认证
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
// GET api/values
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
return new[] { "value1", "value2" };
}
}
}
注意,以上基本完成了 ServiceA 的服务构建,但在实际应用中应做一些修改,例如:IdentityServer 地址应在 appsettings.json 中进行配置,不应把地址分散于项目中各处;认证服务启用最好在全局启用,以防止漏写等等。ServiceB 的内容与 ServiceA 大致相似,因此文章中将不再展示 ServiceB 的构建过程。
Gateway 构建
添加ASP.Net Web

添加空项目

- 打开程序包管理器控制台输入命令:
csharp install-package Ocelot //添加 Ocelotcsharp install-package Ocelot.Provider.Consul // 添加 Consul 服务发现 添加 ocelot.json 文件,内容如下
{
"ReRoutes": [
{
"DownstreamPathTemplate": "/api/{everything}",
"DownstreamScheme": "http",
"UpstreamPathTemplate": "/ServiceA/{everything}",
"UpstreamHttpMethod": [ "GET", "POST", "DELETE", "PUT" ],
"ServiceName": "ServiceA", //consul 服务中 ServiceA 的名称
"LoadBalancerOptions": {
"Type": "LeastConnection"
}
},
{
"DownstreamPathTemplate": "/api/{everything}",
"DownstreamScheme": "http",
"UpstreamPathTemplate": "/ServiceB/{everything}",
"UpstreamHttpMethod": [ "GET", "POST", "DELETE", "PUT" ],
"ServiceName": "ServiceB", //consul 服务中 ServiceB 的名称
"LoadBalancerOptions": {
"Type": "LeastConnection"
}
}
],
"GlobalConfiguration": {
"ServiceDiscoveryProvider": { // Consul 服务发现配置
"Host": "localhost", // Consul 地址
"Port": 8500,
"Type": "Consul"
}
}
}删除 StartUp.cs 文件,在 Program.cs 文件中添加如下内容
using System.IO;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Ocelot.DependencyInjection;
using Ocelot.Middleware;
using Ocelot.Provider.Consul; namespace ApiGateway
{
public class Program
{
public static void Main(string[] args)
{
new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.ConfigureAppConfiguration((hostingContext, config) =>
{
config
.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath)
.AddJsonFile("appsettings.json", true, true)
.AddJsonFile($"appsettings.{hostingContext.HostingEnvironment.EnvironmentName}.json", true, true)
.AddJsonFile("ocelot.json")
.AddEnvironmentVariables();
})
.ConfigureServices(services =>
{
services.AddOcelot().AddConsul();
})
.ConfigureLogging((hostingContext, logging) =>
{
//add your logging
})
.UseIISIntegration()
.Configure(app =>
{
app.UseOcelot().Wait();
})
.Build()
.Run();
}
}
}
注意:打开 Gateway.csproj 文件,更改
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
</PropertyGroup>
为
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
<AspNetCoreHostingModel>OutOfProcess</AspNetCoreHostingModel>
</PropertyGroup>
至此,一个基础网关基本构建完成。
构建 Consul 服务
使用 Chocoletey 安装 Consul,
choco install consul新建一个文件夹以保存 Consul 服务配置

在 consul.d 文件夹中添加配置文件,内容如下:
{
"services": [{
"ID": "ServiceA",
"Name": "ServiceA",
"Tags": [
"ServiceAWebApi", "Api"
],
"Address": "127.0.0.1",
"Port": 8010,
"Check": {
"HTTP": "http://127.0.0.1:8010/Api/health",
"Interval": "10s"
}
}, {
"id": "ServiceB",
"name": "ServiceB",
"tags": [
"ServiceBWebApi","Api"
],
"Address": "127.0.0.1",
"Port": 8011,
"Check": [{
"HTTP": "http://127.0.0.1:8011/Api/health",
"Interval": "10s"
}
]
}
]
}
启动 consul 服务
consul agent -dev -config-dir=./consul.d启动后在浏览器中输入 http://localhost:8500/ui/ 以查看Consul服务

Postman 验证
F5 启动 Gateway 项目,启动 Postman 发送请求到 ServiceA 获取 Token。

使用 Token 请求 ServiceA Values 接口

当尝试使用 ServiceA 获取到的 Token 去获取 ServiceB 的数据时,请求也如意料之中返回 401

总结
至此,一个由 .NET Core、IdentityServer4、Ocelot、Consul实现的基础架构搭建完毕。源码地址
NET Core + Ocelot + IdentityServer4 + Consul的更多相关文章
- 【转】.NET Core + Ocelot + IdentityServer4 + Consul 基础架构实现
作者:Zhang_Xiang 原文地址:.NET Core + Ocelot + IdentityServer4 + Consul 基础架构实现 先决条件 关于 Ocelot 针对使用 .NET 开发 ...
- .NET Core + Ocelot + IdentityServer4 + Consul 基础架构实现
先决条件 关于 Ocelot 针对使用 .NET 开发微服务架构或者面向服务架构提供一个统一访问系统的组件. 参考 本文将使用 Ocelot 构建统一入口的 Gateway. 关于 IdentityS ...
- 分享一个集成.NET Core+Swagger+Consul+Polly+Ocelot+IdentityServer4+Exceptionless+Apollo+SkyWalking的微服务开发框架
集成.NET Core+Swagger+Consul+Polly+Ocelot+IdentityServer4+Exceptionless+Apollo的微服务开发框架 Github源代码地址 htt ...
- .Net Core微服务——网关(2):ocelot集成consul
有consul基础的都知道,consul可以发现新增的服务,剔除掉无效的服务,赋予应用自动伸缩的能力.而ocelot如果集成了consul,那ocelot也能拥有这些能力,还可以自主选择负载均衡策略, ...
- ASP.NET Core OceLot 微服务实践
1.OceLot中间件介绍 在传统的BS应用中,随着业务需求的快速发展变化,需求不断增长,迫切需要一种更加快速高效的软件交付方式.微服务可以弥补单体应用不足,是一种更加快速高效软件架构风格.单体应用被 ...
- 关于Ocelot和Consul 实现GateWay(网关) 服务注册 负载均衡等方面
Ocelot 路由 请求聚合 服务发现 认证 鉴权 限流熔断 内置负载均衡器 Consul 自动服务发现 健康检查 通过Ocelot搭建API网关 服务注册 负载均衡 1. ...
- [翻译] 如何在 ASP.Net Core 中使用 Consul 来存储配置
[翻译] 如何在 ASP.Net Core 中使用 Consul 来存储配置 原文: USING CONSUL FOR STORING THE CONFIGURATION IN ASP.NET COR ...
- Net Core 中使用 Consul 来存储配置
Net Core 中使用 Consul 来存储配置 https://www.cnblogs.com/Rwing/p/consul-configuration-aspnet-core.html 原文: ...
- Asp.Net Core 中IdentityServer4 授权中心之应用实战
一.前言 查阅了大多数相关资料,查阅到的IdentityServer4 的相关文章大多是比较简单并且多是翻译官网的文档编写的,我这里在 Asp.Net Core 中IdentityServer4 的应 ...
随机推荐
- Win10系列:WinJS库控件
在介绍了如何使用标准的HTML控件以及WinJS库中提供的新控件之后,下面来着重介绍WinJS库中几种常用的控件. (1)ListView控件 在开发Windows应用商店应用时可以使用ListVie ...
- laravel 查询指定字段的值
$this->model->where('id',$id)->value('user');
- Kafka.net使用编程入门(一)
最近研究分布式消息队列,分享下! 首先zookeeper 和 kafka 压缩包 解压 并配置好! 我本机zookeeper环境配置如下: D:\Worksoftware\ApacheZookeep ...
- 启动项目时出现java.io.EOFException异常。
错误: 2018-4-18 10:55:54 org.apache.catalina.session.StandardManager doLoad 严重: IOException while load ...
- html页面标题增加图标方法
有些网站的网页标题部分有图标,很带感.方法很简单: 在<head></head>部分增加下列一行代码即可. <link rel="shortcut icon&q ...
- turtle
画一组同切圆 输入 import turtle turtle.color('red') turtle.circle(30) turtle.circle(60) turtle.circle(90) tu ...
- DevExpress v18.1新版亮点——Data Access篇
用户界面套包DevExpress v18.1日前正式发布,本站将以连载的形式为大家介绍各版本新增内容.本文将介绍了DevExpress Data Access v18.1 的新功能,快来下载试用新版本 ...
- easyui 日期控件限制起始相差30天
$('#lendDateStart').datebox('calendar').calendar({ validator: function(date){ var endDateStr = $('#l ...
- openstack网络DVR
一.DVR描述 分布式路由 二.相关的专业术语 术语名称 术语解释 SNAT 在路由器后(POSTROUTING)将内网的ip地址修改为外网网卡的ip地址,也就是绑定浮动IP和外部通信 DNAT 在路 ...
- python中的if判断语句
判断(if)语句 目标 开发中的应用场景 if 语句体验 if 语句进阶 综合应用 01. 开发中的应用场景 生活中的判断几乎是无所不在的,我们每天都在做各种各样的选择,如果这样?如果那样?……  ...