前言:
前一篇文章《.NET Core 微服务—API网关(Ocelot) 教程 [二]》已经让Ocelot和目录api(Api.Catalog)、订单api(Api.Ordering)通过网关方式运行起来了。但在日常开发中Api并不是所有人都能访问的,是添加了认证、授权的。那么本篇文章就将继续介绍Ocelot如何和 IdentityServer4 认证服务如何配合使用的。
创建认证服务(Api.IdentityServer)
1、创建一个空的WebApi项目-Api.IdentityServer,并添加IdentityServer4项目引用:如下图:
Install-Package IdentityServer4
2、要启用IdentityServer服务,不仅要把 IdentityServer 注册到容器中, 还需要配置一下内容:
- Authorization Server 保护了哪些 API (资源);
- 哪些客户端 Client(应用) 可以使用这个 Authorization Server;
- 指定可以使用 Authorization Server 授权的 Users(用户)
a) 创建文件 InMemoryConfig.cs,用于设置以上相关内容:
1 using IdentityServer4;
2 using IdentityServer4.Models;
3 using IdentityServer4.Test;
4 using System;
5 using System.Collections.Generic;
6 using System.Linq;
7 using System.Threading.Tasks;
8
9 namespace Api.IdentityServer
10 {
11 public class InMemoryConfig
12 {
13 public static IEnumerable<IdentityResource> GetIdentityResourceResources()
14 {
15 return new List<IdentityResource>
16 {
17 //必须要添加,否则报无效的scope错误
18 new IdentityResources.OpenId(),
19 };
20 }
21
22 /// <summary>
23 /// api资源列表
24 /// </summary>
25 /// <returns></returns>
26 public static IEnumerable<ApiResource> GetApiResources()
27 {
28 //可访问的API资源(资源名,资源描述)
29 return new List<ApiResource>
30 {
31 new ApiResource("Api.Catalog", "Api.Catalog"),
32 new ApiResource("Api.Ordering", "Api.Ordering")
33 };
34 }
35
36 /// <summary>
37 /// 客户端列表
38 /// </summary>
39 /// <returns></returns>
40 public static IEnumerable<Client> GetClients()
41 {
42 return new List<Client>
43 {
44 new Client
45 {
46 ClientId = "client_Catalog", //访问客户端Id,必须唯一
47 //使用客户端授权模式,客户端只需要clientid和secrets就可以访问对应的api资源。
48 AllowedGrantTypes = GrantTypes.ClientCredentials,
49 ClientSecrets =
50 {
51 new Secret("secret".Sha256())
52 },
53 AllowedScopes = { "Api.Catalog", IdentityServerConstants.StandardScopes.OpenId,IdentityServerConstants.StandardScopes.Profile }
54 },
55 new Client
56 {
57 ClientId = "client_Ordering",
58 ClientSecrets = new [] { new Secret("secret".Sha256()) },
59 //这里使用的是通过用户名密码和ClientCredentials来换取token的方式. ClientCredentials允许Client只使用ClientSecrets来获取token. 这比较适合那种没有用户参与的api动作
60 AllowedGrantTypes = GrantTypes.ResourceOwnerPasswordAndClientCredentials,
61 AllowedScopes = { "Api.Ordering", IdentityServerConstants.StandardScopes.OpenId,IdentityServerConstants.StandardScopes.Profile }
62 }
63 };
64 }
65
66 /// <summary>
67 /// 指定可以使用 Authorization Server 授权的 Users(用户)
68 /// </summary>
69 /// <returns></returns>
70 public static IEnumerable<TestUser> Users()
71 {
72 return new[]
73 {
74 new TestUser
75 {
76 SubjectId = "1",
77 Username = "cba",
78 Password = "abc"
79 }
80 };
81 }
82 }
83 }
View Code
GetApiResources:这里指定了name和display name, 以后api使用authorization server的时候, 这个name一定要一致
GetClients: 认证客户端列表
Users: 这里的内存用户的类型是TestUser, 只适合学习和测试使用, 实际生产环境中还是需要使用数据库来存储用户信息的, 例如接下来会使用asp.net core identity. TestUser的SubjectId是唯一标识.
b) 在Startup.cs中启用IdentityServer服务
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.Hosting;
11 using Microsoft.Extensions.Logging;
12
13 namespace Api.IdentityServer
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.AddControllers();
28
29 services.AddIdentityServer()
30 .AddDeveloperSigningCredential()
31 .AddInMemoryApiResources(InMemoryConfig.GetApiResources())
32 .AddInMemoryClients(InMemoryConfig.GetClients())
33 .AddTestUsers(InMemoryConfig.Users().ToList());
34
35 services.AddAuthentication();//配置认证服务
36 }
37
38 // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
39 public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
40 {
41 if (env.IsDevelopment())
42 {
43 app.UseDeveloperExceptionPage();
44 }
45 app.UseStaticFiles();
46 app.UseRouting();
47
48 app.UseIdentityServer();
49
50 app.UseAuthentication();
51 app.UseAuthorization();
52
53 app.UseEndpoints(endpoints =>
54 {
55 endpoints.MapControllers();
56 });
57 }
58 }
59 }
View Code
为ocelot项目集成IdentityServer
1、添加IdentityServer4.AccessTokenValidation的包,也可以通过程序包管理控制台执行以下命令
Install-Package IdentityServer4.AccessTokenValidation
添加包引用后,在Startup中的 ConfigureServices
中分别注册两个认证方案 Configure
中配置IdentityServer服务。
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication()
.AddJwtBearer("Api.Catalog", i =>
{
i.Audience = "Api.Catalog";
i.Authority = "http://localhost:5332";
i.RequireHttpsMetadata = false;
}).AddJwtBearer("Api.Ordering", y =>
{
y.Audience = "Api.Ordering";
y.Authority = "http://localhost:5331";
y.RequireHttpsMetadata = false;
});
services.AddOcelot();//注入Ocelot服务
services.AddControllers();
}
2、修改ocelot配置文件,在Routes中添加授权信息
调整ApiGateway.Ocelot项目中ocelot.json配置文件如下:
{
"GlobalConfiguration": {
},
"Routes": [
{
"DownstreamPathTemplate": "/api/{controller}/{action}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 5331
}
],
"UpstreamPathTemplate": "/Catalog/{controller}/{action}",
"UpstreamHttpMethod": [ "Get", "Post" ],
"LoadBalancerOptions": {
"Type": "RoundRobin"
},
//授权信息
"AuthenticationOptions": {
"AuthenticationProviderKey": "Api.Catalog",
"AllowedScopes": []
}
},
{
"DownstreamPathTemplate": "/api/{controller}/{action}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 5332
}
],
"UpstreamPathTemplate": "/Ordering/{controller}/{action}",
"UpstreamHttpMethod": [ "Get", "Post" ],
"LoadBalancerOptions": {
"Type": "RoundRobin"
},
//授权信息
"AuthenticationOptions": {
"AuthenticationProviderKey": "Api.Ordering",
"AllowedScopes": []
}
}
]
}
Ocelot会去检查Routes是否配置了AuthenticationOptions节点。如果有会根据配置的认证方案进行身份认证。如果没有则不进行身份认证。
AuthenticationProviderKey 是刚才注册的认证方案。
AllowedScopes 是 AllowedScopes中配置的授权访问范围。
验证效果
1、根据网关设置访问:目录api:http://localhost:5330/Ordering/Values/1
如图:401 Unauthorized 未认证
2、先获取Token后再访问该接口:
根据获取Token在http://localhost:5330/Ordering/Values/1 请求时,添加认证头信息,即可请求成功
回顾总结
1、在IdentityServer注册相关资源服务和客户端信息。
2、Ocelot通过注册认证方案,在配置文件中指定路由的认证方案
3、该认证是在Ocelot网关层对相关资源进行认证,并非资源服务认证
4、认证调用失败时,尝试把IdentityServer包版本降低尝试