asp.net core网关Ocelot的简单介绍& Ocelot集成Identity认证

Posted liumengchen-boke

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了asp.net core网关Ocelot的简单介绍& Ocelot集成Identity认证相关的知识,希望对你有一定的参考价值。

文章简介

  •  Ocelot网关简介

  •  Ocelot集成Idnetity认证处理

Ocelot网关简介

Ocelot是一个基于netcore实现的API网关,本质是一组按特定顺序排列的中间件。Ocelot内部实现了路由转发,限流,熔断,请求聚合,服务发现(集成consul,eureka等),负载均衡,认证(集成Identity)功能。

这里简单介绍下ocelot的配置文件,也就是说以下图为例,请求地址为localhost:18002/users会被转发到localhost:18000/api/users技术图片

更多关于Ocelot的介绍可以看https://www.cnblogs.com/jesse2013/p/net-core-apigateway-ocelot-docs.html这篇博客或者https://ocelot.readthedocs.io/en/latest/index.html官方文档。

Ocelot集成Identity认证

  这里我们实现一个Ocelot集成Idnetity做认证的Demo;我们这里客户端请求ocelot网关服务,ocelot网关服务集成Idnetity获取token,再通过返回的token请求用户信息服务,如下图所示。这里扩展一个知识点,我们的Identity服务使用扩展认证,这个认证需要实现IExtensionGrantValidator接口的ValidateAsync方法,从http请求上下文中获取自定义参数,获取方法为context.Request.Raw。(oauth2默认的认证方式有password,authcode等,扩展认证文档=》http://docs.identityserver.io/en/latest/topics/extension_grants.html?highlight=IExtensionGrantValidator

 技术图片

 首先我们创建三个服务,分别为Ocelot网关服务(端口号设置为18002),Identity认证服务(端口号设置为18001),UserInfo用户信息服务(端口号设置为18000),如下图所示=》技术图片技术图片

 技术图片

  • 首先我们配置User.API服务,这个服务很简单,开放一个返回用户信息的端口,关键代码如下所示 =》 
技术图片
 1 namespace User.API.Controllers
 2 
 3     [Route("api/users")]
 4     public class UserController : BaseController
 5     
 6         private readonly UserContext _userContext;
 7         private ILogger<UserController> _logger;
 8         public UserController(UserContext userContext, ILogger<UserController> logger)
 9         
10             _userContext = userContext;
11             _logger = logger;
12         
13         [HttpGet]
14         public async Task<IActionResult> Get()
15 
16         
17             var user = await _userContext.Set<AppUser>()
18                 .AsNoTracking()
19                 .Include(u => u.userProperties)
20                 .FirstOrDefaultAsync(t => t.Id == 1);
21             if (user == null)
22             
23                 _logger.LogError("登录用户为空");
24                 throw new UserOperationException("用户登录异常");
25             
26             return Json(user);
27         
28 ..... other
User.Api
技术图片
 1         [Route("check_or_create")]
 2         [HttpPost]
 3         public async Task<IActionResult> CheckOrCreate(string phone)
 4         
 5             var user = await _userContext.Users.SingleOrDefaultAsync(u => u.Phone == phone);
 6 
 7             if (user == null)
 8             
 9                 user = new AppUser  Phone = phone ;
10                 _userContext.Users.Add(new AppUser  Phone = phone );
11                 await _userContext.SaveChangesAsync();
12             
13             return Ok(new 
14                 user.Id,
15                 user.Name,
16                 user.Company,
17                 user.Title,
18                 user.Avatar
19             );
20         
User.Api 验证用户手机号,返回用户信息
  • 然后配置我们的Identity认证服务,引入IdnttiyServer4 nuget包,添加Ids4配置文件Config.cs。注意:这里的client_grant_type为sms_auth_code
技术图片
 1     public class Config
 2     
 3         public static IEnumerable<Client> GetClients()
 4         
 5             return new List<Client>
 6                 new Client
 7                     ClientId = "android",
 8                     ClientSecrets = new List<Secret>
 9                     
10                         new Secret("secret".Sha256())
11                     ,
12                     RefreshTokenExpiration  = TokenExpiration.Sliding,
13                     AllowOfflineAccess = true,
14                     RequireClientSecret = false,
15                     AllowedGrantTypes = new List<string>"sms_auth_code",
16                     AlwaysIncludeUserClaimsInIdToken = true,
17                     AllowedScopes = new List<string>
18                     
19                         "gateway_api",
20                         IdentityServerConstants.StandardScopes.OfflineAccess,
21                         IdentityServerConstants.StandardScopes.OpenId,
22                         IdentityServerConstants.StandardScopes.Profile
23                     
24                 
25             ;
26         
27         public static IEnumerable<IdentityResource> GetIdentityResources()
28         
29             return new List<IdentityResource>
30             
31                 new IdentityResources.OpenId(),
32                 new IdentityResources.Profile()
33             ;
34         
35         public static IEnumerable<ApiResource> GetApiResources()
36         
37             return new List<ApiResource>
38             
39                 new ApiResource("gateway_api","user service")
40             ;
41         
42     
Config

  编写我们的自定义自定义验证服务类,我们验证客户端传入的手机号&验证码是否正确(Demo逻辑中只需要填写正确手机号就可以了)

技术图片
 1     public class SmsAuthCodeGrantType : IExtensionGrantValidator
 2     
 3         private IUserService _userService;
 4         private IAuthCodeService _authCodeService;
 5         public SmsAuthCodeGrantType(IUserService userService, IAuthCodeService authCodeService)
 6         
 7             _userService = userService;
 8             _authCodeService = authCodeService;
 9         
10         public string GrantType => "sms_auth_code";
11         /// <summary>
12         /// 
13         /// </summary>
14         /// <param name="context"></param>
15         /// <returns></returns>
16         public async Task ValidateAsync(ExtensionGrantValidationContext context)
17         
18             var phone = context.Request.Raw["phone"];
19             var code = context.Request.Raw["auth_code"];
20             var errorValidationResult = new GrantValidationResult(TokenRequestErrors.InvalidGrant);
21 
22 
23             if (string.IsNullOrWhiteSpace(phone) || string.IsNullOrWhiteSpace(code))
24             
25                 context.Result = errorValidationResult;
26                 return;
27             
28             //检查验证码
29             if (!_authCodeService.Validate(phone, code))
30             
31                 context.Result = errorValidationResult;
32                 return;
33             
34             //完成用户注册
35             var userinfo = await _userService.CheckOrCreate(phone);
36             if (userinfo== null)
37             
38                 context.Result = errorValidationResult;
39                 return;
40             
41             var claims = new Claim[]
42             
43                 new Claim("name",userinfo.Name??string.Empty),
44                 new Claim("company",userinfo.Company??string.Empty),
45                 new Claim("title",userinfo.Tiltle??string.Empty),
46                 new Claim("avatar",userinfo.Avatar??string.Empty),
47             ; 
48             context.Result = new GrantValidationResult(userinfo.Id.ToString(), 
49                 GrantType,
50                 claims);
51         
52     
SmsAuthCodeGrantType

  其他的验证服务和与User.API服务通信的服务类和返回的UserInfoDto

技术图片
1     public class UserInfo
2     
3         public int Id  get; set; 
4         public string Name  get; set; 
5         public string Company  get; set; 
6         public string Tiltle  get; set; 
7         public string Avatar  get; set; 
8     
UserInfo
技术图片
 1     public interface IAuthCodeService
 2     
 3         /// <summary>
 4         /// 根据手机号验证验证码
 5         /// </summary>
 6         /// <param name="phone"></param>
 7         /// <param name="authCode"></param>
 8         /// <returns></returns>
 9         bool Validate(string phone, string authCode);
10     
IAuthCodeService
技术图片
1     public class TestAuthCodeService : IAuthCodeService
2     
3         public bool Validate(string phone, string authCode)
4         
5             return true;
6         
7     
TestAuthCodeService
技术图片
1     public interface IUserService
2     
3         /// <summary>
4         /// 检查手机号是否注册,未注册就注册
5         /// </summary>
6         /// <param name="phone"></param>
7         Task<UserInfo> CheckOrCreate(string phone);
8     
IUserService
技术图片
 1     public class UserService : IUserService
 2     
 3         private HttpClient _httpClient;
 4         private string _userServiceUrl = "http://localhost:18000";
 5         public UserService(HttpClient httpClient)
 6         
 7             _httpClient = httpClient;
 8         
 9 
10         public async Task<UserInfo> CheckOrCreate(string phone)
11         
12             var from = new Dictionary<string, string>
13             
14                  "phone",phone 
15             ;
16             var content = new FormUrlEncodedContent(from);
17             var response = await _httpClient.PostAsync(_userServiceUrl + "/api/users/check_or_create", content);
18             if (response.StatusCode == System.Net.HttpStatusCode.OK)
19             
20                 var result = await response.Content.ReadAsStringAsync();
21                 var userinfo = JsonConvert.DeserializeObject<UserInfo>(result);
22 
23                 //int.TryParse(userId,out int UserIdInt);
24                 return userinfo;
25             
26             return null;
27         
28     
UserService

  配置Startup,注意要在我们的DI容器中注入自定义服务验证类(SmsAuthCodeGrantType)

技术图片
 1     public class Startup
 2     
 3         public Startup(IConfiguration configuration)
 4         
 5             Configuration = configuration;
 6         
 7 
 8         public IConfiguration Configuration  get; 
 9 
10         // This method gets called by the runtime. Use this method to add services to the container.
11         public void ConfigureServices(IServiceCollection services)
12         
13             services.AddMvc();
14             services.AddIdentityServer()
15                 .AddExtensionGrantValidator<SmsAuthCodeGrantType>()  
16                 .AddDeveloperSigningCredential()
17                 .AddInMemoryClients(Config.GetClients())
18                 .AddInMemoryIdentityResources(Config.GetIdentityResources())
19                 .AddInMemoryApiResources(Config.GetApiResources());  //identityserver 认证
20 
21             services.AddScoped<IAuthCodeService, TestAuthCodeService>()
22                 .AddScoped<IUserService, UserService>();
23             services.AddSingleton(new HttpClient());
24         
25 
26         // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
27         public void Configure(IApplicationBuilder app, IHostingEnvironment env)
28         
29             if (env.IsDevelopment())
30             
31                 app.UseDeveloperExceptionPage();
32             
33             app.UseIdentityServer();
34             app.UseMvc();
35         
36     
Startup
  • 最后配置我们的网关Ocelot站点,首先添加nuget包IdentityServer4.AccessTokenValidation和Ocelot。添加配置文件ocelot.json,其实就是博客开头的配置文件截图,这里特别说明下AuthenticationOptions节点,AuthenticationOptions是ocelot集成Identity所需要配置节点,AuthenticationProviderKey需要跟startup的authenticationScheme匹配
技术图片
 1 
 2   "ReRoutes": [
 3     
 4       "DownstreamPathTemplate": "/api/users",
 5       "DownstreamScheme": "http",
 6       "DownstreamHostAndPorts": [
 7         
 8           "Host": "localhost",
 9           "Port": 18000
10         
11       ],
12       "UpstreamPathTemplate": "/users",
13       "UpstreamHttpMethod": [ "Get" ],
14       "AuthenticationOptions": 
15         "AuthenticationProviderKey": "finbook",
16         "AllowedScopes": []
17       
18     ,
19     
20       "DownstreamPathTemplate": "/connect/token",
21       "DownstreamScheme": "http",
22       "DownstreamHostAndPorts": [
23         
24           "Host": "localhost",
25           "Port": 18001
26         
27       ],
28       "UpstreamPathTemplate": "/connect/token",
29       "UpstreamHttpMethod": [ "Post" ]
30     
31   ],
32   "GlobalConfiguration": 
33     "BaseUrl": "http://localhost:18002"
34   
35 
ocelot.json

将配置文件加载到服务中,修改Program的CreateWebHostBuilder方法

技术图片
 1     public class Program
 2     
 3         public static void Main(string[] args)
 4         
 5             CreateWebHostBuilder(args).Build().Run();
 6         
 7 
 8         public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
 9             WebHost.CreateDefaultBuilder(args)
10                 .UseStartup<Startup>()
11                 .UseContentRoot(Directory.GetCurrentDirectory())
12                 .ConfigureAppConfiguration((hostingContext, config) =>
13                 
14                     config
15                        .SetBasePath(hostingContext.HostingEnvironment.ContentRootPath)
16                        //.AddJsonFile("appsettings.json", true, true)
17                        //.AddJsonFile($"appsettings.hostingContext.HostingEnvironment.EnvironmentName.json", true, true)
18                        .AddJsonFile("ocelot.json")
19                        .AddEnvironmentVariables();
20                 )
21                 .UseUrls("http://+:18002");
22     
Program

配置startup,在DI容器中加入Identity自定义认证,加入Ocelot,启用Ocelot中间件

技术图片
 1     public class Startup
 2     
 3         public Startup(IConfiguration configuration)
 4         
 5             Configuration = configuration;
 6         
 7 
 8         public IConfiguration Configuration  get; 
 9 
10         // This method gets called by the runtime. Use this method to add services to the container.
11         public void ConfigureServices(IServiceCollection services)
12         
13             services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
14             //添加 认证信息
15             var authenticationProviderKey = "finbook";
16             services.AddAuthentication()
17                 .AddIdentityServerAuthentication(authenticationProviderKey, options =>
18                 
19                     options.Authority = "http://localhost:18001";
20                     options.ApiName = "gateway_api";
21                     options.SupportedTokens = IdentityServer4.AccessTokenValidation.SupportedTokens.Both;
22                     options.ApiSecret = "secret";
23                     options.RequireHttpsMetadata = false;
24                 );
25             services.AddOcelot();
26         
27 
28         // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
29         public void Configure(IApplicationBuilder app, IHostingEnvironment env)
30         
31             if (env.IsDevelopment())
32             
33                 app.UseDeveloperExceptionPage();
34             
35             else
36             
37                 // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
38                 app.UseHsts();
39             
40             //app.UseAuthentication();
41             app.UseOcelot(); //.Wait()
42             app.UseHttpsRedirection();
43             app.UseMvc();
44         
45     
Startup
  • 验证运行

首先获取token,访问ocelot网关的/connect/token地址,转发到Idnetity服务,注意下grant_type参数要和Identity服务中的配置相同技术图片

接下来根据获取到的token,请求用户信息技术图片

Demo地址=》https://github.com/madeinchinalmc/User.Api

以上是关于asp.net core网关Ocelot的简单介绍& Ocelot集成Identity认证的主要内容,如果未能解决你的问题,请参考以下文章

Api网关Kong集成Consul做服务发现及在Asp.Net Core中的使用

ASP.NET Core 3.1 中的 Ocelot API Gateway 自定义聚合器问题

.NET Core开源API网关 – Ocelot中文文档

.Net Core 基于Ocelot + IdentityServer4 + Eureka的搭建高性能网关介绍

.Net Core with 微服务 - Ocelot 网关

Ocelot- .Net Core开源网关