Fork me on GitHub

小试YARP

 

.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

 

  想要更快更方便的了解相关知识,可以关注微信公众号 
 

 

 

 
posted @ 2022-02-01 14:53  桂素伟  阅读(181)  评论(0编辑  收藏  举报