.NET微服務從0到1:API網關(Ocelot)

Ocelot

Ocelot是用 .NET Core 實現的一個開源API網關。包含身份驗證、路由、請求聚合等功能。能夠輕鬆的集成IdentityServer

Ocelot的五種部署方式

  • 基本使用
    在這裏插入圖片描述

  • 集成IdentityServer
    在這裏插入圖片描述

  • 多實例
    在這裏插入圖片描述

  • 集成Consul
    在這裏插入圖片描述

  • 集成 Service Fabric
    在這裏插入圖片描述

開始使用

新建網關項目

新建一個Web項目ApiGateways,添加nuget包引用

Install-Package Ocelot

在這裏插入圖片描述

添加ocelot配置文件

  • ocelot.json
{
    "ReRoutes": [
        {
        "DownstreamPathTemplate": "/todos/{id}",
        "DownstreamScheme": "https",
        "DownstreamHostAndPorts": [
            {
                "Host": "jsonplaceholder.typicode.com",
                "Port": 443
            }
        ],
        "UpstreamPathTemplate": "/todos/{id}",
        "UpstreamHttpMethod": [ "Get" ]
        }
    ],
    "GlobalConfiguration": {
        "BaseUrl": "https://localhost:5000"
    }
}

此配置中,ReRoutes節點下的Downstream相關節點表示網關下游服務相關配置,以上,我們指定了任意請求都以https請求轉發,其中DownstreamHostAndPorts表示下游服務地址和端口。Upstream表示上游請求配置

  • 配置服務引入oeclot.json
public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureAppConfiguration((hostingContext, config) =>
        {
            config.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath)
            .AddJsonFile("ocelot.json")
            .AddEnvironmentVariables();
        })
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseStartup<Startup>();
        });

此配置中,我們的網關服務運行在http://localhost,其中AuthenticationOptions是認證服務相關配置,另外有一個下游服務運行在http://localhost:5201

將Ocelot服務添加到容器服務

public void ConfigureServices(IServiceCollection services)
{
    services.AddOcelot();
}

將Ocelot添加請求管道

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
	app.UseOcelot();
}

創建身份認證服務

新建一個Identity.API項目

添加nuget

Install-Package IdentityServer4 -Version 3.1.2

在這裏插入圖片描述

添加IdentityServer4配置

  • IdentityServer4 配置
    爲便於展示,不做持久化,寫在內存中
public static class Config
{
    // Defining an API Resource
    public static IEnumerable<ApiResource> Apis => new List<ApiResource>
    {
        new ApiResource("gateway_api","ApiGateways")
    };

    // Defining Client
    public static IEnumerable<Client> Clients => new List<Client>
    {
        new Client
        {
            ClientId="app_test",

            // no interactive user, use the clientid/secret for authentication
            AllowedGrantTypes=GrantTypes.ClientCredentials,

            // secret for authentication
            ClientSecrets={
                new Secret("123456".Sha256())
            },

            // scopes that client has access to
            AllowedScopes=new List<string>{
                "gateway_api",
            }
        }
    };

    // Defineing Identity Resource
    public static IEnumerable<IdentityResource> IdentityResources => new List<IdentityResource>
    {
        new IdentityResources.OpenId(),
        new IdentityResources.Profile(),
    };
}
  • 添加IdentityServer4到容器
public void ConfigureDevelopmentServices(IServiceCollection services)
{
    var builder = services.AddIdentityServer()
        .AddInMemoryApiResources(Config.Apis)
        .AddInMemoryClients(Config.Clients)
        .AddInMemoryIdentityResources(Config.IdentityResources);
    builder.AddDeveloperSigningCredential();
    services.AddControllers();
}
  • 添加IdentityServer4到請求管道
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseHttpsRedirection();
    app.UseRouting();
    app.UseIdentityServer();
    app.UseAuthorization();
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });
}

創建一個ServiceA

在這裏插入圖片描述
我們將在ServiceA中提供一個簡單服務:爲一個用戶打一個標籤

    [Route("[controller]")]
    [ApiController]
    public class UserController : ControllerBase
    {
        [HttpPost]
        [Route("tag/create")]
        public IActionResult CreateTag([FromForm]int userId, [FromForm]string value)
        {
            // 假設數據庫記錄添加成功,直接返回對象
            Tag tagEntity = new Tag();
            tagEntity.Id = 1;
            tagEntity.UserId = userId;
            tagEntity.Value = value;
            return Ok(tagEntity);
        }
    }
    public class Tag
    {
        public int Id { get; set; }
        public int UserId { get; set; }
        public string Value { get; set; }
    }

終章

支持我們三個項目已經建立完成,但要通過網關身份認證服務請求到創建標籤的服務,我們還需要對網關服務做一些修改。
首先,在ocelot.json新增AuthenticationOptions配置IdentityServer4身份認證服務中對應的資源

{
  "ReRoutes": [
    {
      "DownstreamPathTemplate": "/{url}",
      "DownstreamScheme": "http",
      "DownstreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": 5201
        }
      ],
      "UpstreamPathTemplate": "/service-a/{url}",
      "UpstreamHttpMethod": [ "Get", "Post" ],
      "AuthenticationOptions": {
        "AuthenticationProviderKey": "SampleKey",
        "AllowedScopes": [ "gateway_api" ]
      }
    }
  ],
  "GlobalConfiguration": {
    "BaseUrl": "http://localhost"
  }
}

其中http://localhost:5201是我們ServiceA運行的地址

然後我們需要注入認證服務到容器

Install-Package IdentityServer4.AccessTokenValidation -Version 3.0.1

public void ConfigureServices(IServiceCollection services)
{
    var authenticationProviderKey = "SampleKey";
    Action<IdentityServerAuthenticationOptions> options = o =>
    {
        o.Authority = "http://localhost:5200";
        o.ApiName = "gateway_api";
        o.SupportedTokens = SupportedTokens.Both;
        o.ApiSecret = "123456";
        o.RequireHttpsMetadata = false;
    };

    services.AddAuthentication()
        .AddIdentityServerAuthentication(authenticationProviderKey, options);
    services.AddOcelot();
}

其中http://localhost:5200是我們認證服務運行的地址

  • 通過網關直接調用
    在這裏插入圖片描述
    我們發現返回401未授權,這是正常的,因爲我們爲網關服務添加了認證服務。

  • 通過token訪問

我們首先要去拿token,我們現在暫時先通過postman直接獲取token
在這裏插入圖片描述
通過token訪問
在這裏插入圖片描述
我們可以看到已經成功請求到了創建用戶標籤接口

參考

Ocelot官方文檔
.NET Core開源API網關 – Ocelot中文文檔

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章