首页 > Web开发 > 详细

【转】.NET Core + Ocelot + IdentityServer4 + Consul 基础架构实现

时间:2019-05-25 21:59:32      阅读:132      评论:0      收藏:0      [点我收藏+]

作者:Zhang_Xiang

原文地址:.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 文件,并添加内容如下:

 1 using IdentityServer4.Models;
 2 using IdentityServer4.Test;
 3 using System;
 4 using System.Collections.Generic;
 5 using System.Linq;
 6 using System.Threading.Tasks;
 7 
 8 namespace IdentityServer
 9 {
10     public sealed class Config
11     {
12         public static IEnumerable<ApiResource> GetApiResources()
13         {
14             return new List<ApiResource>
15              {
16                  new ApiResource("ServiceA", "ServiceA API"),
17                  new ApiResource("ServiceB", "ServiceB API")
18              };
19         }
20 
21         public static IEnumerable<Client> GetClients()
22         {
23             return new List<Client>
24              {
25                  new Client
26                  {
27                      ClientId = "ServiceAClient",
28                      AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
29                      ClientSecrets =
30                      {
31                          new Secret("ServiceAClient".Sha256())
32                      },
33                      AllowedScopes = new List<string> {"ServiceA"},
34                      AccessTokenLifetime = 60 * 60 * 1
35                  },
36                  new Client
37                  {
38                      ClientId = "ServiceBClient",
39                      AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
40                      ClientSecrets =
41                      {
42                          new Secret("ServiceBClient".Sha256())
43                      },
44                      AllowedScopes = new List<string> {"ServiceB"},
45                      AccessTokenLifetime = 60 * 60 * 1
46                  }
47              };
48         }
49 
50         public static List<TestUser> GetUsers()
51         {
52             return new List<TestUser>
53              {
54                  new TestUser
55                  {
56                      Username = "test",
57                      Password = "123456",
58                      SubjectId = "1"
59                  }
60              };
61         }
62 
63         public static IEnumerable<IdentityResource> GetIdentityResources()
64         {
65             return new List<IdentityResource>();
66         }
67     }
68 }

注意:这里添加了两个 Client ,分别为 ServiceA、ServiceB ,因此接下来将构建这两个服务。

5.修改Startup文件

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Threading.Tasks;
 5 using Microsoft.AspNetCore.Builder;
 6 using Microsoft.AspNetCore.Hosting;
 7 using Microsoft.AspNetCore.Http;
 8 using Microsoft.Extensions.DependencyInjection;
 9 
10 namespace IdentityServer
11 {
12     public class Startup
13     {
14         // This method gets called by the runtime. Use this method to add services to the container.
15         // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
16         public void ConfigureServices(IServiceCollection services)
17         {
18             services.AddMvc().SetCompatibilityVersion(Microsoft.AspNetCore.Mvc.CompatibilityVersion.Version_2_2);
19             services.AddIdentityServer()
20                 .AddDeveloperSigningCredential()
21                 .AddInMemoryIdentityResources(Config.GetIdentityResources())
22                 .AddInMemoryApiResources(Config.GetApiResources())
23                 .AddInMemoryClients(Config.GetClients())
24                 .AddTestUsers(Config.GetUsers());
25         }
26 
27         // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
28         public void Configure(IApplicationBuilder app, IHostingEnvironment env)
29         {
30             if (env.IsDevelopment())
31             {
32                 app.UseDeveloperExceptionPage();
33             }
34 
35             app.UseIdentityServer();
36 
37             app.Run(async (context) =>
38             {
39                 await context.Response.WriteAsync("Hello World!");
40             });
41         }
42     }
43 }

注意:AddDeveloperSigningCredential() 方法用于添加开发时使用的 Key material ,生产环境中不要使用该方法。在 .NET Core 2.2 中新建的 Web 项目文件 csproj 中包含了如下内容:

<PropertyGroup>
  <TargetFramework>netcoreapp2.2</TargetFramework> 
  <AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel> 
</PropertyGroup>

这里更改

<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>

为或直接删除该行,这么做的原因是当值为 InProcess 时,读写 tempkey.rsa 将产生权限问题。关于 AspNetCoreHostingModel 可参考 ASP.NET Core Module 。

<AspNetCoreHostingModel>OutOfProcess</AspNetCoreHostingModel>

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

技术分享图片

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

技术分享图片

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

构建 ServiceA、ServiceB

  1.添加 ASP.Net Core Web 项目,这里以 ServiceA 为例进行构建

技术分享图片

  2.添加 ASP.Net Core API

技术分享图片

  3.在程序包管理控制台中运行

    Install-Package IdentityModel

  4.在 StartUp.cs 中添加内容如下:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Threading.Tasks;
 5 using Microsoft.AspNetCore.Builder;
 6 using Microsoft.AspNetCore.Hosting;
 7 using Microsoft.AspNetCore.Mvc;
 8 using Microsoft.Extensions.Configuration;
 9 using Microsoft.Extensions.DependencyInjection;
10 using Microsoft.Extensions.Logging;
11 using Microsoft.Extensions.Options;
12 
13 namespace ServiceA
14 {
15     public class Startup
16     {
17         public Startup(IConfiguration configuration)
18         {
19             Configuration = configuration;
20         }
21 
22         public IConfiguration Configuration { get; }
23 
24         // This method gets called by the runtime. Use this method to add services to the container.
25         public void ConfigureServices(IServiceCollection services)
26         {
27             services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
28             services.AddAuthentication("Bearer")
29                 .AddJwtBearer("Bearer", options =>
30                 {
31                     options.Authority = "http://localhost:3518";
32                     options.RequireHttpsMetadata = false;
33                     options.Audience = "ServiceA";
34                 });
35         }
36 
37         // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
38         public void Configure(IApplicationBuilder app, IHostingEnvironment env)
39         {
40             if (env.IsDevelopment())
41             {
42                 app.UseDeveloperExceptionPage();
43             }
44             app.UseAuthentication();
45             app.UseMvc();
46         }
47     }
48 }

  5.添加 SessionController 用于用户登录,内容如下:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.ComponentModel.DataAnnotations;
 4 using System.Linq;
 5 using System.Net.Http;
 6 using System.Threading.Tasks;
 7 using IdentityModel.Client;
 8 using Microsoft.AspNetCore.Http;
 9 using Microsoft.AspNetCore.Mvc;
10 
11 namespace ServiceA.Controllers
12 {
13     [Route("api/[controller]")]
14     [ApiController]
15     public class SessionController : ControllerBase
16     {
17         public async Task<string> Login(UserRequestModel userRequestModel)
18         {
19             var client = new HttpClient();
20             DiscoveryResponse disco =  await client.GetDiscoveryDocumentAsync("http://localhost:3518");
21             if (disco.IsError)
22             {
23                 return "认证服务未启动";
24             }
25             TokenResponse tokenResponse = await client.RequestPasswordTokenAsync(new PasswordTokenRequest
26             {
27                 Address = disco.TokenEndpoint,
28                 ClientId = "ServiceAClient",
29                 ClientSecret = "ServiceAClient",
30                 UserName = userRequestModel.Name,
31                 Password = userRequestModel.Password
32             });
33             return tokenResponse.IsError ? tokenResponse.Error : tokenResponse.AccessToken;
34         }
35     }
36     public class UserRequestModel
37     {
38         [Required(ErrorMessage = "用户名称不可以为空")]
39         public string Name { get; set; }
40 
41         [Required(ErrorMessage = "用户密码不可以为空")]
42         public string Password { get; set; }
43     }
44 }

  6.添加 HealthController 用于 Consul 进行服务健康检查,内容如下:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Threading.Tasks;
 5 using Microsoft.AspNetCore.Http;
 6 using Microsoft.AspNetCore.Mvc;
 7 
 8 namespace ServiceA.Controllers
 9 {
10     [Route("api/[controller]")]
11     [ApiController]
12     public class HealthController : ControllerBase
13     {
14         /// <summary>
15         /// 健康检查
16         /// </summary>
17         /// <returns></returns>
18         public IActionResult Get()
19         {
20             return Ok();
21         }
22     }
23 }

  7.更改 ValuesController.cs 内容如下:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Threading.Tasks;
 5 using Microsoft.AspNetCore.Authorization;
 6 using Microsoft.AspNetCore.Mvc;
 7 
 8 namespace ServiceA.Controllers
 9 {
10     [Authorize] //添加 Authorize Attribute 以使该控制器启用认证
11     [Route("api/[controller]")]
12     [ApiController]
13     public class ValuesController : ControllerBase
14     {
15         [HttpGet]
16         public ActionResult<IEnumerable<string>> Get()
17         {
18             return new string[] { "value1", "value2" };
19         }
20     }
21 }

注意,以上基本完成了 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 文件,内容如下

 1 {
 2   "ReRoutes": [
 3     {
 4       "DownstreamPathTemplate": "/api/{everything}",
 5       "DownstreamScheme": "http",
 6       "UpstreamPathTemplate": "/ServiceA/{everything}",
 7       "UpstreamHttpMethod": [ "GET", "POST", "DELETE", "PUT" ],
 8       "ServiceName": "ServiceA", //consul 服务中 ServiceA 的名称
 9       "LoadBalancerOptions": {
10         "Type": "LeastConnection"
11       }
12     },
13     {
14       "DownstreamPathTemplate": "/api/{everything}",
15       "DownstreamScheme": "http",
16       "UpstreamPathTemplate": "/ServiceB/{everything}",
17       "UpstreamHttpMethod": [ "GET", "POST", "DELETE", "PUT" ],
18       "ServiceName": "ServiceB", //consul 服务中 ServiceB 的名称
19       "LoadBalancerOptions": {
20         "Type": "LeastConnection"
21       }
22     }
23   ],
24   "GlobalConfiguration": {
25     "ServiceDiscoveryProvider": { // Consul 服务发现配置
26       "Host": "localhost", // Consul 地址
27       "Port": 8500,
28       "Type": "Consul"
29     }
30   }
31 }

  5.删除 StartUp.cs 文件,在 Program.cs 文件中添加如下内容

 1 using System;
 2 using System.Collections.Generic;
 3 using System.IO;
 4 using System.Linq;
 5 using System.Threading.Tasks;
 6 using Microsoft.AspNetCore;
 7 using Microsoft.AspNetCore.Hosting;
 8 using Microsoft.Extensions.Configuration;
 9 using Microsoft.Extensions.Logging;
10 using Ocelot.DependencyInjection;
11 using Ocelot.Middleware;
12 using Ocelot.Provider.Consul;
13 
14 namespace ApiGateway
15 {
16     public class Program
17     {
18         public static void Main(string[] args)
19         {
20             CreateWebHostBuilder(args).Build().Run();
21         }
22 
23         public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
24             WebHost.CreateDefaultBuilder(args)
25             .ConfigureAppConfiguration((context, builder) =>
26             {
27                 builder.SetBasePath(context.HostingEnvironment.ContentRootPath);
28                 builder.AddJsonFile("appsettings.json", true, true);
29                 builder.AddJsonFile($"appsettings.{context.HostingEnvironment.EnvironmentName}.json", true, true);
30                 builder.AddJsonFile("ocelot.json");
31                 builder.AddEnvironmentVariables();
32             })
33             .ConfigureServices(services =>
34             {
35                 services.AddOcelot().AddConsul();
36             })
37             .ConfigureLogging((hostingContext, logging) =>
38             {
39                 //add your logging
40             })
41             .Configure(app =>
42             {
43                 app.UseOcelot().Wait();
44             });
45     }
46 }

注意:打开 ApiGateway.csproj 文件,更改

  <PropertyGroup>
    <TargetFramework>netcoreapp2.2</TargetFramework>
    <AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
  </PropertyGroup>

  <PropertyGroup>
    <TargetFramework>netcoreapp2.2</TargetFramework>
    <AspNetCoreHostingModel>OutOfProcess</AspNetCoreHostingModel>
  </PropertyGroup>

至此,一个基础网关基本构建完成。

 

【转】.NET Core + Ocelot + IdentityServer4 + Consul 基础架构实现

原文:https://www.cnblogs.com/fanqisoft/p/10924009.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!