.net core下,一个轻量组反向代理库,由微软发起。
做了一个简单的带验证的反向代理,应用结构如上图,一个验证服务,两个业务服务和一个YARP服务。
源码
https://github.com/axzxs2001/Asp.NetCoreExperiment/tree/master/Asp.NetCoreExperiment/YARP
YARP的Starup.cs如下,主要是用来添加YARP组件和添加权限组件部分。
using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using System.IdentityModel.Tokens.Jwt; using Microsoft.IdentityModel.Tokens; using Microsoft.Extensions.Hosting; using System.Collections.Generic; using System.Security.Claims; using System.Threading.Tasks; using System.Text; using System; namespace YARPDemo01 { public class Startup { public IConfiguration Configuration { get; } public Startup(IConfiguration configuration) { Configuration = configuration; } public void ConfigureServices(IServiceCollection services) { AddAuth(services); services.AddReverseProxy().LoadFromConfig(Configuration.GetSection("ReverseProxy")); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseAuthentication(); app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapReverseProxy(); }); } void AddAuth(IServiceCollection services) { //读取配置文件 var audienceConfig = Configuration.GetSection("Audience"); var symmetricKeyAsBase64 = audienceConfig["Secret"]; var keyByteArray = Encoding.ASCII.GetBytes(symmetricKeyAsBase64); var signingKey = new SymmetricSecurityKey(keyByteArray); var tokenValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true, IssuerSigningKey = signingKey, ValidateIssuer = true, ValidIssuer = audienceConfig["Issuer"], ValidateAudience = true, ValidAudience = audienceConfig["Audience"], ValidateLifetime = true, ClockSkew = TimeSpan.Zero, RequireExpirationTime = true, }; var signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256); //这个集合模拟用户权限表,可从数据库中查询出来 var permission = new List<Permission> { new Permission { Url="/webapi01/test1", Name="admin"}, new Permission { Url="/webapi01/test3", Name="admin"}, new Permission { Url="/webapi02/test2", Name="admin"}, new Permission { Url="/webapi02/test4", Name="admin"}, }; //如果第三个参数,是ClaimTypes.Role,上面集合的每个元素的Name为角色名称,如果ClaimTypes.Name,即上面集合的每个元素的Name为用户名 var permissionRequirement = new PermissionRequirement( "/api/denied", permission, ClaimTypes.Role, audienceConfig["Issuer"], audienceConfig["Audience"], signingCredentials, expiration: TimeSpan.FromSeconds(1000000)//设置Token过期时间 ); services.AddAuthorization(options => { options.AddPolicy("Permission", policy => policy.AddRequirements(permissionRequirement)); }). AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, o => { //不使用https o.RequireHttpsMetadata = false; o.TokenValidationParameters = tokenValidationParameters; o.Events = new JwtBearerEvents { OnTokenValidated = context => { if (context.Request.Path.Value.ToString() == "/api/logout") { var token = ((context as TokenValidatedContext).SecurityToken as JwtSecurityToken).RawData; } return Task.CompletedTask; } }; }); //注入授权Handler services.AddSingleton<IAuthorizationHandler, PermissionHandler>(); services.AddSingleton(permissionRequirement); } } }
YARP项目实现API聚合appsettings.json
{ "urls": "https://*:6001;http://*:6000", "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } }, "AllowedHosts": "*", "Audience": { "Secret": "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890", "Issuer": "gsw", "Audience": "everone" }, //实现api聚合 "ReverseProxy": { "Routes": [ //业务服务webapi01 { "RouteId": "webapi01", "ClusterId": "webapi01_cluster", "AuthorizationPolicy": "Permission", "Match": { "Path": "/webapi01/{**catch-all}" } }, //业务服务webapi02 { "RouteId": "webapi02", "ClusterId": "webapi02_cluster", "AuthorizationPolicy": "Permission", "Match": { "Path": "/webapi02/{**catch-all}" } }, //验证服务 { "RouteId": "authservice", "ClusterId": "auth_cluster", "Match": { "Path": "/auth/{**catch-all}" } } ], "Clusters": { //业务服务webapi01 "webapi01_cluster": { "Destinations": { "webapi01_cluster/destination": { "Address": "https://localhost:7001/" } } }, //业务服务webapi02 "webapi02_cluster": { "Destinations": { "webapi02_cluster/destination": { "Address": "https://localhost:8001/" } } }, //验证服务 "auth_cluster": { "Destinations": { "auth_cluster/destination": { "Address": "https://localhost:5001/" } } } } } }
Auth项目实现登录签名部分
using System; using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; namespace AuthenticationAuthorization_Token { public class JwtToken { /// <summary> /// 获取基于JWT的Token /// </summary> /// <param name="username"></param> /// <returns></returns> public static dynamic BuildJwtToken(Claim[] claims, PermissionRequirement permissionRequirement) { var now = DateTime.UtcNow; var jwt = new JwtSecurityToken( issuer: permissionRequirement.Issuer, audience: permissionRequirement.Audience, claims: claims, notBefore: now, expires: now.Add(permissionRequirement.Expiration), signingCredentials: permissionRequirement.SigningCredentials ); var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt); var response = new { Status = true, access_token = encodedJwt, expires_in = permissionRequirement.Expiration.TotalMilliseconds, token_type = "Bearer" }; return response; } } }
看结果:
首先登录获取token,用户名gsw,密码111111
访问webapi01
访问webapi02
想要更快更方便的了解相关知识,可以关注微信公众号