.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 服务

  1. 添加 ASP.Net Core Web 项目
  2. 添加空项目
  3. 在程序包管理控制台中输入:Install-Package IdentityServer4.AspNetIdentity
  4. 添加 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 ,因此接下来将构建这两个服务。

  5. 删掉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>

  6. F5 启动该服务,显示如下:

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

至此,一个包含两个服务认证的认证服务搭建完毕。

构建 ServiceA、ServiceB

  1. 添加 ASP.Net Core Web 项目,这里以 ServiceA 为例进行构建
  2. 添加 ASP.Net Core API
  3. 在程序包管理控制台中运行
    Install-Package IdentityModel
  4. 在 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();
             }
         }
     }
    
  5. 添加 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; }
         }
     }
  6. 添加 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();
             }
         }
     }
  7. 更改 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 构建

  1. 添加ASP.Net Web
  2. 添加空项目
  3. 打开程序包管理器控制台输入命令:
    csharp install-package Ocelot //添加 Ocelot
    csharp install-package Ocelot.Provider.Consul // 添加 Consul 服务发现
  4. 添加 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"
         }
     }
     }
  5. 删除 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 服务

  1. 使用 Chocoletey 安装 Consul,

    choco install consul
  2. 新建一个文件夹以保存 Consul 服务配置
  3. 在 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"
                        }
                    ]
                }
            ]
        }
    
  4. 启动 consul 服务
    consul agent -dev -config-dir=./consul.d

    启动后在浏览器中输入 http://localhost:8500/ui/ 以查看Consul服务

Postman 验证

  1. F5 启动 Gateway 项目,启动 Postman 发送请求到 ServiceA 获取 Token。
  2. 使用 Token 请求 ServiceA Values 接口
  3. 当尝试使用 ServiceA 获取到的 Token 去获取 ServiceB 的数据时,请求也如意料之中返回 401

总结

至此,一个由 .NET Core、IdentityServer4、Ocelot、Consul实现的基础架构搭建完毕。源码地址

原文地址:https://www.cnblogs.com/webenh/p/12394106.html

时间: 2024-11-05 19:35:10

.NET Core + Ocelot + IdentityServer4 + Consul 基础架构实现的相关文章

ASP.NET Core OceLot 微服务实践

1.OceLot中间件介绍 在传统的BS应用中,随着业务需求的快速发展变化,需求不断增长,迫切需要一种更加快速高效的软件交付方式.微服务可以弥补单体应用不足,是一种更加快速高效软件架构风格.单体应用被分解成多个更小的服务,每个服务有自己的独立模块,单独部署,然后共同组成一个应用程序.把范围限定到单个独立业务模块功能.分布式部署在各台服务器上. 而Ocelot开发的目标就是使用.NET运行面向微服务/服务的架构,要达到这个目标需要一个统的系统入口点(我们统称为API网关),同时需要与Identit

.NET Core微服务系列基础文章

今年从原来的Team里面被抽出来加入了新的Team,开始做Java微服务的开发工作,接触了Spring Boot, Spring Cloud等技术栈,对微服务这种架构有了一个感性的认识.虽然只做了两个月的开发工作,但是对微服务架构的兴趣却没有结束,又因为自己的.NET背景(虽然对.NET的生态有点恨铁不成钢),想要探索一下在.NET平台下的微服务架构的可行性,也准备一些材料作为分享的素材. 幸运的是,在.NET Core首届在线峰会上,看到了很多前辈的分享,也增强了自己要摸索和实践.NET Co

Asp.Net Core 中IdentityServer4 实战之 Claim详解

一.前言 由于疫情原因,让我开始了以博客的方式来学习和分享技术(持续分享的过程也是自己学习成长的过程),同时也让更多的初学者学习到相关知识,如果我的文章中有分析不到位的地方,还请大家多多指教:以后我会持续更新我的文章,望大家多多支持和关注. 上几篇文章主要分享了IdentityServer4在Asp.Net Core 3.x 中的应用,在上面的几篇分享中有一部分博友问了我这么一个问题"他通过IdentityServer4 来搭建授权中心网关服务,怎么才能在访问受保护的Api资源中获取到用户的相关

b2c项目基础架构分析(一)

我最近一直在找适合将来用于公司大型bs,b2b b2c的基础架构. 实际情况是要建立一个bs架构b2b.b2c的网站,当然还包括wap站点.手机app站点. 一.现有公司技术人员现状: 1.熟悉asp.net页面级开发.页面级处理的后端人员. 基本特点:掌握小型单站.单页的相关开发技术. 技术熟练度为:asp.net原理基础.asp.net webform控件中等.jquery基础.js初步到基础.sql基础到中等. 面对大型站点可能存在的弊端: a.不熟悉大型环境的架构: b.对站点.页面在大

ng2文档学习(一、基础架构)

这张是ng2的基础架构全景图. 文档的示例都是ts语法! 都是一些自己的看文档的一些的摘抄,有一起学的小伙伴留言一起研究下哈 模块(module) angular有自己的模块系统,称为angular模块或者NgModules 每个angular至少有一个模块(AppModule根模块,大多数应用会有很多特性模块) angular模块都是一个带有@NgModule装饰器的类 装饰器是用来修饰javascript类的函数,负责将元数据加到类上 NgModule是一个装饰器函数,参数为一个描述模块属性

HashiCorp:为任何应用程序提供安全和可运行的基础架构

HashiCorp 由Mitchell Hashimoto和Armon Dadgar于2012年创办,总部位于美国旧金山. HashiCorp致力于解决基础架构中的开发.维护及安全所面临的挑战. HashiCorp提供的Cloud和DevOps基础设施自动化工具,集开发.运营和安全性于一体,包括Vagrant.Packer.Terraform.Vault.Nomad和Consul六款产品,可以帮助开发和部署应用程序,加速应用程序分发,助力企业提升开发效率. HashiCorp通过提出跨越差距的解

Consul的使用一 之Consul的架构

Consul的架构 如下图所示: 通常情况下, 一个数据中心由client和server组成, 并且需要保证server相对较少, 因为server越多, server之间达成一致的速度越慢. 一个数据中心的所有agent都参与一个gossip协议. Consul使用gossip协议来管理集群中的成员关系, 广播消息到集群中.所有的这些都是通过Serf库实现的, serf使用的gossip协议是SWIM(Scalable Weakly-consistent infection-style pro

Asp.Net Core 中IdentityServer4 实战之角色授权详解

一.前言 前几篇文章分享了IdentityServer4密码模式的基本授权及自定义授权等方式,最近由于改造一个网关服务,用到了IdentityServer4的授权,改造过程中发现比较适合基于Role角色的授权,通过不同的角色来限制用户访问不同的Api资源,这里我就来分享IdentityServer4基于角色的授权详解. IdentityServer4 历史文章目录 Asp.Net Core IdentityServer4 中的基本概念 Asp.Net Core 中IdentityServer4

【Windows】Windows Server 2008 R2:核心基础架构

核心基础架构 Windows Server提供了核心基础架构服务以支持网络的运行.Windows Server技术已经成熟了,其中的角色和功能也同样成熟了.Windows Server 2008 R2继续改进了核心基础架构服务,这些服务一直都是Windows Server的一部分,它们为我们的业务提供了一个稳固的基础.点击以下核心基础架构角色以了解更多: Active Directory(AD) 应用程序和Web服务 可用性和可量测性 备份和恢复-Windows Server Backup Br