文章简介

  •  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 == );
  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. if (string.IsNullOrWhiteSpace(phone) || string.IsNullOrWhiteSpace(code))
  23. {
  24. context.Result = errorValidationResult;
  25. return;
  26. }
  27. //检查验证码
  28. if (!_authCodeService.Validate(phone, code))
  29. {
  30. context.Result = errorValidationResult;
  31. return;
  32. }
  33. //完成用户注册
  34. var userinfo = await _userService.CheckOrCreate(phone);
  35. if (userinfo== null)
  36. {
  37. context.Result = errorValidationResult;
  38. return;
  39. }
  40. var claims = new Claim[]
  41. {
  42. new Claim("name",userinfo.Name??string.Empty),
  43. new Claim("company",userinfo.Company??string.Empty),
  44. new Claim("title",userinfo.Tiltle??string.Empty),
  45. new Claim("avatar",userinfo.Avatar??string.Empty),
  46. };
  47. context.Result = new GrantValidationResult(userinfo.Id.ToString(),
  48. GrantType,
  49. claims);
  50. }
  51. }

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":
  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":
  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认证的更多相关文章

  1. ASP.NET Core 中的 Razor 页面介绍

    标题:ASP.NET Core 中的 Razor 页面介绍 地址:https://docs.microsoft.com/zh-cn/aspnet/core/razor-pages/index?view ...

  2. ASP.NET Core应用程序容器化、持续集成与Kubernetes集群部署(一)(转载)

    本文结构 ASP.NET Core应用程序的构建 ASP.NET Core应用程序容器化所需注意的问题 应用程序的配置信息 端口侦听 ASP.NET Core的容器版本 docker镜像构建上下文(B ...

  3. asp.net core系列 53 IdentityServer4 (IS4)介绍

    一.概述 在物理层之间相互通信必须保护资源,需要实现身份验证和授权,通常针对同一个用户存储.对于资源安全设计包括二个部分,一个是认证,一个是API访问. 1 认证 认证是指:应用程序需要知道当前用户的 ...

  4. ASP.NET Core身份认证服务框架IdentityServer4 介绍

    IdentityServer4是ASP.NET Core 2的OpenID Connect和OAuth 2.0框架.它可以在您的应用程序中提供以下功能: 它使你的应用程序具有如下特点: 认证即服务 适 ...

  5. Workflow Core + asp.net core 5.0 实现简单审批工作流

    我们知道企业业务系统到处都可以审批工作流的,但也很少有像OA系统一样复杂多级多条件的审批工作流需要设计,所以我们需要一个轻量级的容易上手的workflow框架,通过GitHub,我发现danielge ...

  6. Asp.net core与golang web简单对比测试

    最近因为工作需要接触了go语言,又恰好asp.net core发布RC2,就想简单做个对比测试. 下面是测试环境: CPU:E3-1230 v2 内存:16G 电脑有点不给力 操作系统:Centos7 ...

  7. 在ASP.NET Core MVC中构建简单 Web Api

    Getting Started 在 ASP.NET Core MVC 框架中,ASP.NET 团队为我们提供了一整套的用于构建一个 Web 中的各种部分所需的套件,那么有些时候我们只需要做一个简单的 ...

  8. 基于Asp.Net Core 2.1的简单问答社区系统源代码分享

    看见园子里很多人都在分享源代码,我也来凑个热闹. 该项目基于.NET CORE 2.1(其实是从1.1开始开发的),经历过不停的调整终于有个能拿出手的版本了,第一次在博客园发文章. 使用到的技术以及框 ...

  9. asp.net core系列 72 Exceptionless使用介绍

    一.Exceptionless介绍 Exceptionless专注于.net平台提供实时错误和日志报告.主要包括:错误通知.智能分组异常.详细错误报告堆栈跟踪.支持离线.UI查看重要错误和确定优先级. ...

随机推荐

  1. 小程序 页面传值 json 被截断

    因此解决这个报错的方法是将要传输的数据用 encodeURIComponent()函数(可把字符串作为 URI 组件进行编码) 先进行编码, 传输过去后再通过decodeURIComponent()函 ...

  2. 15. Django连接Mysql数据库

    安装PyMySQL,打开cmd, pip install PyMySQL 在.../blog/init.py 目录下添加: import pymysql pymysql.install_as_MySQ ...

  3. interleave two text files with specified lines

    a_file=$1 a_step=$2 b_file=$3 b_step=$4 a_start=1 let a_end=$a_start+$a_step b_start=1 let b_end=$b_ ...

  4. python- 粘包 struct,socketserver

    黏包 黏包现象 让我们基于tcp先制作一个远程执行命令的程序(命令ls -l ; lllllll ; pwd) res=subprocess.Popen(cmd.decode('utf-8'), sh ...

  5. 菩提圣心诀---zabbix自定义key监控oracle连接状态(python脚本)

    目的:此次实验目的是为了zabbix服务端能够实时监控某服务器上oracle实例能否正常连接 环境:1.zabbix_server 2.zabbix_agent(含有oracle) 主要知识点: 1. ...

  6. GCD 与XOR

    题目:UVA12716 题意:  问 gcd(i,j) = i ^ j  的对数(j <=i <= N ) N的范围为30000000,有10000组样例 分析: 有几个结论:(1)若 a ...

  7. 微信小程序生命周期、页面生命周期、组件生命周期

    1. 生命周期 App(全局) 位置:项目根目录app.js文件 App({ onLaunch (options) { // console.log('小程序初始化') }, onShow(optio ...

  8. Web开发进阶

    1.可靠性 可扩展性,服务降级,负载均衡   应用扩展 1.垂直扩展,方式:提升机器硬件,缺点,成本昂贵,扩展能力有限 2.水平扩展,方式:增加节点,优点:升级过程平花,硬件成本低,理论上无线扩展,确 ...

  9. Oracle多表更新及MERGE命令和闪回机制还原数据表

    一.多表更新 比如线上有个系统由于某一个模块出现异常,导致系统整体的数据出现了错误,需要你手动改写数据库错误,Oracle update语句更新的值来自另一张表 update语法最基本的格式为 UPD ...

  10. hdu 5791 思维dp

    题目描述: 求序列A,B的公共子序列个数: 基本思路: 想到了dp,选的状态也对,但是就是就是写不出状态转移方程,然后他们都出了,到最后我还是没出,很难受,然后主要是没有仔细考虑dp[i][j],dp ...