zoukankan      html  css  js  c++  java
  • 使用Ocelot、IdentityServer4、Spring Cloud Eureka搭建微服务网关:Step by Step(二)

    本文继续介绍使用Ocelot、IdentityServer4以及Spring Cloud Eureka搭建微服务网关的步骤。相关文章:

    Step 4:引入Ocelot API网关

    新建一个ASP.NET Core API项目,添加对以下NuGet包的引用:

    • Ocelot
    • IdentityServer4
    • IdentityServer4.AccessTokenValidation
    • Serilog(我使用了Serilog来输出格式化的日志,如果不使用Serilog,则不需要引用)

    首先,修改Startup.cs文件,用来启用Ocelot,并指定身份认证机构为之前我们建好的IdentityServer服务:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
        services.AddAuthentication()
            .AddIdentityServerAuthentication("AuthProviderKey", options =>
            {
                options.Authority = "http://localhost:5000";
                options.RequireHttpsMetadata = false;
                options.ApiName = "country_code_api";
                options.SupportedTokens = SupportedTokens.Both;
            });
    
        services.AddOcelot();
    }
    
    // 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.UseMvc();
        app.UseOcelot().Wait();
    }

    注意代码中的高亮部分,分别指定了身份认证机构的URL地址、所需认证的API名称,以及对Ocelot网关的启用。接下来,需要配置Ocelot网关,使其在充当网关角色的同时,完成身份验证的过程。下面的JSON文件(ocelot.config.json)对API网关的Upstream、Downstream以及身份认证相关信息进行了设置。注意,在每个API的AuthenticationOptions设置中,AuthenticationProviderKey应该使用上面Startup.cs中指定的那个Key(也就是AddIdentityServerAuthentication方法的第一个参数)。

    {
      "ReRoutes": [
        {
          "DownstreamPathTemplate": "/api/countries",
          "DownstreamScheme": "http",
          "DownstreamHostAndPorts": [
            {
              "Host": "localhost",
              "Port": 5001
            }
          ],
          "UpstreamPathTemplate": "/countries",
          "UpstreamHttpMethod": [ "Get" ],
          "AuthenticationOptions": {
            "AuthenticationProviderKey": "AuthProviderKey",
            "AllowedScopes": []
          }
        },
        {
          "DownstreamPathTemplate": "/api/countries/{code}",
          "DownstreamScheme": "http",
          "DownstreamHostAndPorts": [
            {
              "Host": "localhost",
              "Port": 5001
            }
          ],
          "UpstreamPathTemplate": "/countries/{code}",
          "UpstreamHttpMethod": [ "Get" ],
          "AuthenticationOptions": {
            "AuthenticationProviderKey": "AuthProviderKey",
            "AllowedScopes": []
          }
        }
      ],
      "GlobalConfiguration": {
        "RequestIdKey": "OcRequestId",
        "AdministrationPath": "/administration"
      }
    }

    然后,修改Program.cs文件,将ocelot.config.json文件加入项目的配置系统中,以便Ocelot能够读取并使用里面的配置。当然,如果不打算使用Serilog,可以忽略UseSerilog的相关设置。

    public static IWebHostBuilder CreateWebHostBuilder(string[] args)
    {
        return WebHost.CreateDefaultBuilder(args)
        .UseStartup<Startup>()
        .ConfigureAppConfiguration((context, builder) =>
        {
            builder.AddJsonFile("ocelot.config.json");
        })
        .UseSerilog((context, logger) =>
        {
            logger.ReadFrom.Configuration(context.Configuration);
        });
    }
    

    最后,修改launchSettings.json,使得Ocelot API网关侦听5002端口。于是,有关Ocelot网关的加入和基本配置就完成了。如果需要了解Ocelot使用的更多信息,可以参考我之前的文章《ASP.NET Core中Ocelot的使用:API网关的应用》。

    Step 5:通过Ocelot API网关访问API

    在本系列文章第一篇中所演示的控制台应用程序中,做一些小的改动,即可实现通过Ocelot API网关访问需身份认证的API。我们只需要将API的访问地址从原来的直接访问的URL,改为Ocelot所配置的URL即可:

    static async Task Main(string[] args)
    {
        using (var client = new HttpClient())
        {
            // IdentityModel为HttpClient提供了基于认证模型的API扩展
            // 获取Access Token
            var discoResponse = await client.GetDiscoveryDocumentAsync("http://localhost:5000");
            if (discoResponse.IsError)
            {
                Console.WriteLine(discoResponse.Error);
                return;
            }
    
            var tokenResponse = await client.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest
            {
                Address = discoResponse.TokenEndpoint,
                ClientId = "country_api_client",
                ClientSecret = "abcdef",
                Scope = "country_code_api"
            });
    
            if (tokenResponse.IsError)
            {
                Console.WriteLine(tokenResponse.Error);
                return;
            }
    
            // 输出获取Access Token的API返回结果
            Console.WriteLine(tokenResponse.Json);
    
            // 在HttpClient上设置Access Token
            client.SetBearerToken(tokenResponse.AccessToken);
    
            // 调用API并返回结果
            var response = await client.GetAsync("http://localhost:5002/countries/cn");
            Console.WriteLine(response.IsSuccessStatusCode ?
                $"{response.StatusCode} {await response.Content.ReadAsStringAsync()}" : response.StatusCode.ToString());
        }
    }
    

    现在,启动身份认证服务IdentityServer、Countries API服务、Ocelot API网关,然后运行控制台应用程序,可以看到,API可以正常返回并输出正确结果:

    image

    接下来做个试验,就是注释掉Countries API上的Authorize特性,让Countries API在没有认证的情况下也能被访问,然后,再次启动IdentityServer、Countries API服务以及Ocelot网关服务,再直接使用cURL进行调用,此时我们没有提供任何认证的令牌信息,可以看到,服务端拒绝了我们的请求,并返回了HTTP 401 Unauthorized:

    image

    由此可见,即便是API没有实现认证机制,Ocelot API网关也能代理完成认证的功能,这也使得一个微服务的项目能够通过API网关来统一完成身份认证,背后的API无需考虑身份认证的工作(授权是另一个概念,今后会讨论)。

    小结

    本文简要介绍了如何接入Ocelot API网关,结合IdentityServer4完成微服务API的身份认证。后续的文章会讨论另一个话题:授权。以下是本文所描述场景的UML时序图,供参考:

    [plantuml]

    @startuml IdsSample_Chapter2_Sequence

    actor ClientApp

    ClientApp -> IdentityServer: getAccessToken

    IdentityServer --> ClientApp: accessToken

    ClientApp -> OcelotAPIGateway: getCountriesByCode(countryCode, accessToken)

    OcelotAPIGateway -> IdentityServer: authenticate(accessToken)

    IdentityServer --> OcelotAPIGateway: success

    OcelotAPIGateway -> CountriesAPI: getCountriesByCode(countryCode)

    CountriesAPI -> CountriesAPI: findCountriesByCode(countryCode)

    CountriesAPI --> OcelotAPIGateway: countries

    OcelotAPIGateway --> ClientApp: countries

    @enduml

    [/plantuml]

  • 相关阅读:
    eureka流程图
    Feign和Ribbon的重试机制
    idea编译kafka 2.6 源码
    Feign的调用流程
    FeignClientFactoryBean创建动态代理
    Feign源码的入口
    Ribbon的检查服务
    Ribbon是怎么和Eureka整合的?
    Eureka过期
    backup: sqlHelper --cSharp
  • 原文地址:https://www.cnblogs.com/daxnet/p/12941761.html
Copyright © 2011-2022 走看看