文章简介

  •  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服务,这个服务很简单,开放一个返回用户信息的端口,关键代码如下所示 =》
 namespace User.API.Controllers
{
[Route("api/users")]
public class UserController : BaseController
{
private readonly UserContext _userContext;
private ILogger<UserController> _logger;
public UserController(UserContext userContext, ILogger<UserController> logger)
{
_userContext = userContext;
_logger = logger;
}
[HttpGet]
public async Task<IActionResult> Get() {
var user = await _userContext.Set<AppUser>()
.AsNoTracking()
.Include(u => u.userProperties)
.FirstOrDefaultAsync(t => t.Id == );
if (user == null)
{
_logger.LogError("登录用户为空");
throw new UserOperationException("用户登录异常");
}
return Json(user);
}
..... other

User.Api

         [Route("check_or_create")]
[HttpPost]
public async Task<IActionResult> CheckOrCreate(string phone)
{
var user = await _userContext.Users.SingleOrDefaultAsync(u => u.Phone == phone); if (user == null)
{
user = new AppUser { Phone = phone };
_userContext.Users.Add(new AppUser { Phone = phone });
await _userContext.SaveChangesAsync();
}
return Ok(new {
user.Id,
user.Name,
user.Company,
user.Title,
user.Avatar
});
}

User.Api 验证用户手机号,返回用户信息

  • 然后配置我们的Identity认证服务,引入IdnttiyServer4 nuget包,添加Ids4配置文件Config.cs。注意:这里的client_grant_type为sms_auth_code
     public class Config
{
public static IEnumerable<Client> GetClients()
{
return new List<Client>{
new Client{
ClientId = "android",
ClientSecrets = new List<Secret>
{
new Secret("secret".Sha256())
},
RefreshTokenExpiration = TokenExpiration.Sliding,
AllowOfflineAccess = true,
RequireClientSecret = false,
AllowedGrantTypes = new List<string>{"sms_auth_code"},
AlwaysIncludeUserClaimsInIdToken = true,
AllowedScopes = new List<string>
{
"gateway_api",
IdentityServerConstants.StandardScopes.OfflineAccess,
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile
}
}
};
}
public static IEnumerable<IdentityResource> GetIdentityResources()
{
return new List<IdentityResource>
{
new IdentityResources.OpenId(),
new IdentityResources.Profile()
};
}
public static IEnumerable<ApiResource> GetApiResources()
{
return new List<ApiResource>
{
new ApiResource("gateway_api","user service")
};
}
}

Config

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

     public class SmsAuthCodeGrantType : IExtensionGrantValidator
{
private IUserService _userService;
private IAuthCodeService _authCodeService;
public SmsAuthCodeGrantType(IUserService userService, IAuthCodeService authCodeService)
{
_userService = userService;
_authCodeService = authCodeService;
}
public string GrantType => "sms_auth_code";
/// <summary>
///
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public async Task ValidateAsync(ExtensionGrantValidationContext context)
{
var phone = context.Request.Raw["phone"];
var code = context.Request.Raw["auth_code"];
var errorValidationResult = new GrantValidationResult(TokenRequestErrors.InvalidGrant); if (string.IsNullOrWhiteSpace(phone) || string.IsNullOrWhiteSpace(code))
{
context.Result = errorValidationResult;
return;
}
//检查验证码
if (!_authCodeService.Validate(phone, code))
{
context.Result = errorValidationResult;
return;
}
//完成用户注册
var userinfo = await _userService.CheckOrCreate(phone);
if (userinfo== null)
{
context.Result = errorValidationResult;
return;
}
var claims = new Claim[]
{
new Claim("name",userinfo.Name??string.Empty),
new Claim("company",userinfo.Company??string.Empty),
new Claim("title",userinfo.Tiltle??string.Empty),
new Claim("avatar",userinfo.Avatar??string.Empty),
};
context.Result = new GrantValidationResult(userinfo.Id.ToString(),
GrantType,
claims);
}
}

SmsAuthCodeGrantType

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

     public class UserInfo
{
public int Id { get; set; }
public string Name { get; set; }
public string Company { get; set; }
public string Tiltle { get; set; }
public string Avatar { get; set; }
}

UserInfo

     public interface IAuthCodeService
{
/// <summary>
/// 根据手机号验证验证码
/// </summary>
/// <param name="phone"></param>
/// <param name="authCode"></param>
/// <returns></returns>
bool Validate(string phone, string authCode);
}

IAuthCodeService

     public class TestAuthCodeService : IAuthCodeService
{
public bool Validate(string phone, string authCode)
{
return true;
}
}

TestAuthCodeService

     public interface IUserService
{
/// <summary>
/// 检查手机号是否注册,未注册就注册
/// </summary>
/// <param name="phone"></param>
Task<UserInfo> CheckOrCreate(string phone);
}

IUserService

     public class UserService : IUserService
{
private HttpClient _httpClient;
private string _userServiceUrl = "http://localhost:18000";
public UserService(HttpClient httpClient)
{
_httpClient = httpClient;
} public async Task<UserInfo> CheckOrCreate(string phone)
{
var from = new Dictionary<string, string>
{
{ "phone",phone }
};
var content = new FormUrlEncodedContent(from);
var response = await _httpClient.PostAsync(_userServiceUrl + "/api/users/check_or_create", content);
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
var result = await response.Content.ReadAsStringAsync();
var userinfo = JsonConvert.DeserializeObject<UserInfo>(result); //int.TryParse(userId,out int UserIdInt);
return userinfo;
}
return null;
}
}

UserService

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

     public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
} public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddIdentityServer()
.AddExtensionGrantValidator<SmsAuthCodeGrantType>()
.AddDeveloperSigningCredential()
.AddInMemoryClients(Config.GetClients())
.AddInMemoryIdentityResources(Config.GetIdentityResources())
.AddInMemoryApiResources(Config.GetApiResources()); //identityserver 认证 services.AddScoped<IAuthCodeService, TestAuthCodeService>()
.AddScoped<IUserService, UserService>();
services.AddSingleton(new HttpClient());
} // 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.UseIdentityServer();
app.UseMvc();
}
}

Startup

  • 最后配置我们的网关Ocelot站点,首先添加nuget包IdentityServer4.AccessTokenValidation和Ocelot。添加配置文件ocelot.json,其实就是博客开头的配置文件截图,这里特别说明下AuthenticationOptions节点,AuthenticationOptions是ocelot集成Identity所需要配置节点,AuthenticationProviderKey需要跟startup的authenticationScheme匹配
 {
"ReRoutes": [
{
"DownstreamPathTemplate": "/api/users",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port":
}
],
"UpstreamPathTemplate": "/users",
"UpstreamHttpMethod": [ "Get" ],
"AuthenticationOptions": {
"AuthenticationProviderKey": "finbook",
"AllowedScopes": []
}
},
{
"DownstreamPathTemplate": "/connect/token",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port":
}
],
"UpstreamPathTemplate": "/connect/token",
"UpstreamHttpMethod": [ "Post" ]
}
],
"GlobalConfiguration": {
"BaseUrl": "http://localhost:18002"
}
}

ocelot.json

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

     public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
} public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.UseContentRoot(Directory.GetCurrentDirectory())
.ConfigureAppConfiguration((hostingContext, config) =>
{
config
.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath)
//.AddJsonFile("appsettings.json", true, true)
//.AddJsonFile($"appsettings.{hostingContext.HostingEnvironment.EnvironmentName}.json", true, true)
.AddJsonFile("ocelot.json")
.AddEnvironmentVariables();
})
.UseUrls("http://+:18002");
}

Program

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

     public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
} public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
//添加 认证信息
var authenticationProviderKey = "finbook";
services.AddAuthentication()
.AddIdentityServerAuthentication(authenticationProviderKey, options =>
{
options.Authority = "http://localhost:18001";
options.ApiName = "gateway_api";
options.SupportedTokens = IdentityServer4.AccessTokenValidation.SupportedTokens.Both;
options.ApiSecret = "secret";
options.RequireHttpsMetadata = false;
});
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();
}
else
{
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
//app.UseAuthentication();
app.UseOcelot(); //.Wait()
app.UseHttpsRedirection();
app.UseMvc();
}
}

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. Mysql安装和简单设置

    MySQL安装文件分为两种,一种是msi格式的,一种是zip格式的.如果是msi格式的可以直接点击安装,按照它给出的安装提示进行安装(相信大家的英文可以看懂英文提示),一般MySQL将会安装在C:\P ...

  2. 耗时十个月的德国APS,教会我的学习方法

    考过了准备了10个月的Aps ,想送给关注我的8175个粉丝,一份礼物,感谢你们看的起我,对我的支持和关注. 这份礼物,我就大言不惭的称之为:达令的学习方法. 我的考试经历:高考两次,中戏艺考三试,导 ...

  3. 原来... 用debug如何查看当前标志寄存器的标志位值?

    -r 用这个指令,得到的信息右下角: NV   UP   EI   PL   NZ   NA   PO   NC这些符号代表的就是标志寄存器里常用标志位的值. 这个是符号值对应表: 溢出标志OF(Ov ...

  4. java并发编程笔记(三)——线程安全性

    java并发编程笔记(三)--线程安全性 线程安全性: ​ 当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些进程将如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现 ...

  5. RabbitMQ(七)心跳控制 -- heartbeat

    https://blog.csdn.net/jiao_fuyou/article/details/23186407

  6. browser-sync浏览器同步刷新工具

    > https://browsersync.io1. 安装browser-sync2. 切换到相应的目录,要监视的文件目录3. 启动browser-sync监视css文件: `browser-s ...

  7. CPython,PyPy?Python和这两个东西有什么关系

    https://blog.csdn.net/fu6543210/article/details/90770794 python是一种编程语言.但这种语言有多种实现,而且与其他语言不同,python并没 ...

  8. java多线程学习笔记(三)

    java多线程下的对象及变量的并发访问 上一节讲到,并发访问的时候,因为是多线程,变量如果不加锁的话,会出现“脏读”的现象,这个时候需要“临界区”的出现去解决多线程的安全的并发访问.(这个“脏读”的现 ...

  9. python 包管理工具 pip 的配置

    近几年来,python的包管理系统pip 越来越完善, 尤其是对于 windows场景下,pip大大改善了python的易用性. https://www.cnblogs.com/yvivid/p/pi ...

  10. texinfo - 软件文档系统

    DESCRIPTION 描述 Texinfo 是一种文档系统,使用单一的源文件来产生在线文档以及可打印的输出.它主要用于书写软件使用手册. 要查看 Texinfo 语言和相关工具的全面描述,请查看 T ...