本文继续介绍使用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可以正常返回并输出正确结果:
接下来做个试验,就是注释掉Countries API上的Authorize特性,让Countries API在没有认证的情况下也能被访问,然后,再次启动IdentityServer、Countries API服务以及Ocelot网关服务,再直接使用cURL进行调用,此时我们没有提供任何认证的令牌信息,可以看到,服务端拒绝了我们的请求,并返回了HTTP 401 Unauthorized:
由此可见,即便是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]
来源:oschina
链接:https://my.oschina.net/u/4330033/blog/4289273