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

    网上这部分的文章和资料很多,有一篇非常不错的文章(《Net Core 基于Ocelot+IdentityServer4+Eureka的搭建高性能网关介绍》),也介绍了这个内容,我也是参考了其中的某些步骤,一步一步演练下来,感觉.NET Core在微服务生态方面也是越来越成熟,功能也越来越强大。因此,我也撰写记录一下整个步骤,通过Step by Step的形式,加上一些注解,以及对于一些遇到的坑的描述,将整个实践过程记录下来,以便帮到有需要的读者,也为自己的学习做个记录。我不会再在概念性的问题上多费笔墨,比如什么是API网关、Ocelot、IdentityServer4、Eureka又是什么之类的问题,我不会做过多的说明,我会争取用最简单快捷的方式,将相关的实践内容描述清楚,虽然本文的标题后面加了一个“(一)”的字样,代表还会有后续的文章,因为我觉得一篇估计讲不完。

    案例场景

    在我之前写的《.NET Core中Ocelot的使用》系列文章中,我设计了一个场景,同时涉及了两个微服务的RESTful API,当时使用两个微服务,不仅是为了介绍API网关的主要功能,而且还引入了服务发现的内容,因此,使用两个微服务来演示会比较合理。当然,今天我们已经学习过API网关和服务发现的基本知识了,我就进一步将案例场景简化,我们只做一个API:Countries API,在这个API中,会有两个API端点(API Endpoint):
    • GET /api/countries:获取世界上所有国家的名称(Name)以及它们的代码(Code)
    • GET /api/countries/{code}:通过国家代码,获取国家的信息
    当这两个API被调用时,会从countries.json文件中读入数据并返回结果。countries.json文件的内容大致如下:
    [
      {
        "name": "Afghanistan",
        "code": "AF"
      },
      {
        "name": "Albania",
        "code": "AL"
      }
      // ......
    ]
    非常简单。下面我们就一步步地实现整个微服务网关的基础架构。

    Step 1:实现Countries API

    新建ASP.NET Core API应用程序,在Linux或者MacOS下,可以使用dotnet new命令行创建,在Windows下,也可以使用Visual Studio自带的项目模板(需要安装ASP.NET Core Workload)创建。然后新建Countries控制器,代码如下:
    [Route("api/[controller]")]
    [ApiController]
    public class CountriesController : ControllerBase
    {
        private readonly ILogger logger;
    
        public CountriesController(ILogger<CountriesController> logger) => this.logger = logger;
    
        private static readonly Lazy<List<Country>> countries = new Lazy<List<Country>>(() 
            => JsonConvert.DeserializeObject<List<Country>>(System.IO.File.ReadAllText("countries.json")));
    
        [HttpGet]
        public IEnumerable<Country> Get() => countries.Value;
    
        [HttpGet("{code}")]
        public IEnumerable<Country> GetByCode(string code) => countries.Value.Where(c => string.Equals(c.Code, code, StringComparison.InvariantCultureIgnoreCase));
    }
    
    按需设置launchSettings.json文件,设置侦听端口和启动方式。这里我选择命令行方式,侦听5001端口,启动项目,使用curl对API进行测试: image

    Step 2:使用Identity Server 4提供认证服务

    新建一个新的ASP.NET Core MVC应用程序,将其作为API的认证机构(Authentication Authority)。你也可以根据需要使用ASP.NET Core API或者空的ASP.NET Core项目作为基础来开发这个认证机构服务,不过为了今后的进一步介绍,我这里选择MVC作为项目模板。在这个项目中,添加对IdentityServer4这一NuGet包的依赖,然后对Startup.cs进行以下修改。 首先,在Startup.cs中加入如下方法,对API资源、访问API的客户端以及认证资源进行配置:
    private static IEnumerable<ApiResource> GetApis()
        => new[]
        {
            new ApiResource("country_code_api", "Country Code API")
        };
    
    private static IEnumerable<Client> GetClients()
        => new[]
        {
            new Client
            {
                ClientId = "country_api_client",
                AllowedGrantTypes = GrantTypes.ClientCredentials,
                ClientSecrets =
                {
                    new Secret("abcdef".Sha256())
                },
                AllowedScopes = { "country_code_api" }
            }
        };
    
    private static IEnumerable<IdentityResource> GetIdentityResources()
        => new IdentityResource[]
        {
            new IdentityResources.OpenId(),
            new IdentityResources.Profile()
        };
    
    然后,在ConfigureServices方法中,加入对Identity Server 4的配置:
    public void ConfigureServices(IServiceCollection services)
    {
        services.Configure<CookiePolicyOptions>(options =>
        {
            // This lambda determines whether user consent for non-essential cookies is needed for a given request.
            options.CheckConsentNeeded = context => true;
            options.MinimumSameSitePolicy = SameSiteMode.None;
        });
    
        services.AddIdentityServer()
            .AddDeveloperSigningCredential()
            .AddInMemoryIdentityResources(GetIdentityResources())
            .AddInMemoryApiResources(GetApis())
            .AddInMemoryClients(GetClients());
    
    
        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    }
    
    最后,在Configure方法中,启用Identity Server 4:
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/Error");
        }
    
        app.UseStaticFiles();
        app.UseCookiePolicy();
        app.UseIdentityServer();
        app.UseMvc();
    }
    
    同样,根据需要修改launchSettings.json文件,然后启动该项目,可以通过http://localhost:5000/.well-known/openid-configuration这一端点来获得OpenID配置的元数据: image

    Step 3:使用Identity Server 4认证服务对API访问进行身份认证

    接下来,修改Countries API,使其使用上面的Identity Server进行API访问认证。修改Countries API项目的Startup.cs文件中的ConfigureServices和Configure方法,加入以下代码:
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
        services.AddAuthentication("Bearer")
            .AddJwtBearer("Bearer", options =>
            {
                options.Authority = "http://localhost:5000";
                options.RequireHttpsMetadata = false;
                options.Audience = "country_code_api";
            });
    }
    
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        app.UseAuthentication();
        app.UseMvc();
    }
    
    在上面的方法中,通过options.Authority属性设置认证机构为我们的Identity Server的地址,然后再在ContriesController上添加Authorize特性,表示Controller需要身份认证:
    [Route("api/[controller]")]
    [ApiController]
    [Authorize]
    public class CountriesController : ControllerBase
    {
        // ...
    }
    
    此时启动Identity Server,然后重启Contries API项目,再次使用curl测试,发现请求已经返回401 Unauthorized状态: image 因为我们没有提供任何Access Token,所以也就无法访问Countries API。目前我们使用的访问方式还是最简单的Client Credentials,后面我们会使用Password的方式来改造我们的认证形式,以实现用户注册、认证等应用场景。现在,我们新建一个控制台应用程序,在这个控制台应用程序上,添加IdentityModel的NuGet依赖项,然后使用下面的代码访问Countries API:
    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:5001/api/countries/cn");
            Console.WriteLine(response.IsSuccessStatusCode ?
                $"{response.StatusCode} {await response.Content.ReadAsStringAsync()}" : response.StatusCode.ToString());
        }
    }
    运行后可以看到,程序可以输出正确结果: image

    小结

    本文以最快速的方式展示了如何让ASP.NET Core Web API基于Identity Server 4实现身份认证,我们暂时还没有引入Ocelot API网关,也没有引入API访问授权、用户注册与登录等等内容,这些都会在后续文章中一步步介绍。由于牵涉的内容真的非常多,文章没有办法把所有细节内容一一解释完整,因此如果在阅读上存在疑惑,请在文章下方留言,我会一一回复。下一讲会介绍如何在Ocelot API网关上整合Identity Server 4的认证服务。 以下是本文所描述的场景的UML时序图,供参考: [plantuml] @startuml IdsSample_Chapter1_Sequence actor ClientApp ClientApp -> IdentityServer: getAccessToken IdentityServer --> ClientApp: accessToken ClientApp -> CountriesAPI: getCountriesByCode(countryCode, accessToken) CountriesAPI -> IdentityServer: authenticate(accessToken) IdentityServer --> CountriesAPI: success CountriesAPI -> CountriesAPI: findCountriesByCode(countryCode) CountriesAPI --> ClientApp: countries @enduml [/plantuml]
  • 相关阅读:
    PL/SQL连接错误:ora-12705:cannot access NLS data files or invalid environment specified
    java 后台开发关键词解释
    架构、框架和设计模式关系(转)
    Web.xml配置详解
    SVN“验证位置时发生错误”的解决办法
    java遍历给定目录,树形结构输出所有文件,包括子目录中的文件
    android EditText 默认情况下不获取焦点(不弹出输入框)
    android listview item取消按点击效果
    如何实现可动态调整隐藏header的listview
    eclipse 启动到loading workbench... 自动关闭
  • 原文地址:https://www.cnblogs.com/daxnet/p/12941759.html
Copyright © 2011-2022 走看看