silky微服务定义了三种类型的代理主机,开发者可以根据需要选择合适的silky代理主机托管微服务应用。代理主机定义了一个Startup模块,该模块给出了使用该种类型主机所必须依赖的模块。

该类型的主机一般用于托管业务应用,服务内部之间通过rpc进行通信,不支持与微服务集群与外部进行通信,web代理主机可以通过引用该类型的微服务的应用接口,通过应用接口生成的代理与该微服务进行通信。该类型的微服务使用.net的通用主机进行托管引用。定义的Startup模块如下所示:

  1. [DependsOn(typeof(ZookeeperModule),
  2. typeof(DotNettyTcpModule),
  3. typeof(RpcProxyModule),
  4. typeof(TransactionTccModule),
  5. typeof(ValidationModule),
  6. typeof(FluentValidationModule),
  7. typeof(RedisCachingModule),
  8. typeof(TransactionRepositoryRedisModule)
  9. )]
  10. public abstract class GeneralHostModule : StartUpModule
  11. {
  12. }

开发者如果需要创建一个微服务应用,只需要在创建一个控制台应用,通过nuget包管理工具安装Silky.Agent.GeneralHost包,在主函数中注册SilkyServices,并指定启动模块即可。

  1. public static async Task Main(string[] args)
  2. {
  3. await CreateHostBuilder(args).Build().RunAsync();
  4. }
  5. private static IHostBuilder CreateHostBuilder(string[] args)
  6. {
  7. return Host.CreateDefaultBuilder(args)
  8. .RegisterSilkyServices<AccountHostModule>()
  9. ;
  10. }

开发者通过继承GeneralHostModule模块定义启动模块。可以通过DependsOn依赖自定义的模块或是Silky提供的模块。

启动模块如下所示:

  1. //
  2. // [DependsOn(typeof(SilkySkyApmAgentModule),
  3. // typeof(JwtModule),
  4. // typeof(MessagePackModule))]
  5. public class AccountHostModule : GeneralHostModule
  6. {
  7. }

该类型的主机可以通过http端口与外部通过http协议进行通信,通过引用其他业务微服务应用的应用接口,根据路由模版生成restful风格的webapi,开发者可以通过配置生成在线的swagger文档。直观的看到在线api文档和进行调试。生成的swagger文档可以根据引用的应用接口进行分组。

image

web代理主机预定义的Startup模块指定了web代理主机必须依赖的silky模块,如下所示:

  1. [DependsOn(typeof(RpcProxyModule),
  2. typeof(ZookeeperModule),
  3. typeof(SilkyHttpCoreModule),
  4. typeof(DotNettyModule),
  5. typeof(ValidationModule),
  6. typeof(FluentValidationModule),
  7. typeof(RedisCachingModule)
  8. )]
  9. public abstract class WebHostModule : StartUpModule
  10. {
  11. }

该类型的主机一般用于网关,提供了外部与微服务集群进行通信的桥梁,该类型的主机使用.net的web主机进行托管应用。开发者可以创建一个aspnetcore项目,通过安装Silky.Agent.WebHost包即可创建web代理主机,需要同时指定启动模块和Startup类。

  1. public async static Task Main(string[] args)
  2. {
  3. await CreateHostBuilder(args).Build().RunAsync();
  4. }
  5. public static IHostBuilder CreateHostBuilder(string[] args)
  6. {
  7. var hostBuilder = Host.CreateDefaultBuilder(args)
  8. .RegisterSilkyServices<GatewayHostModule>()
  9. .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); });
  10. return hostBuilder;
  11. }

web代理主机的启动模块需要继承WebHostModule,启动模块GatewayHostModule如下所示:

  1. public class GatewayHostModule : WebHostModule
  2. {
  3. }

需要在Startup类注册Silky请求管道,Startup类如下所示:

  1. public class Startup
  2. {
  3. public Startup(IConfiguration configuration)
  4. {
  5. Configuration = configuration;
  6. }
  7. public IConfiguration Configuration { get; }
  8. // This method gets called by the runtime. Use this method to add services to the container.
  9. public void ConfigureServices(IServiceCollection services)
  10. {
  11. }
  12. // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
  13. public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
  14. {
  15. if (env.IsDevelopment() || env.EnvironmentName == "ContainerDev")
  16. {
  17. app.UseDeveloperExceptionPage();
  18. }
  19. app.ConfigureSilkyRequestPipeline();
  20. }
  21. }

websocket代理主机与通用代理主机基本一致,websocket代理主机具体提供ws服务的能力,web主机可以通过ws代理与websocket代理主机的ws服务进行通信。

websocket代理主机的启动模块如下所示:

  1. [DependsOn(typeof(ZookeeperModule),
  2. typeof(DotNettyTcpModule),
  3. typeof(RpcProxyModule),
  4. typeof(TransactionTccModule),
  5. typeof(WebSocketModule),
  6. typeof(ValidationModule),
  7. typeof(FluentValidationModule),
  8. typeof(RedisCachingModule),
  9. typeof(TransactionRepositoryRedisModule)
  10. )]
  11. public abstract class WebSocketHostModule : StartUpModule
  12. {
  13. }

开发者可以通过WebSocket配置节点对ws服务进行配置,ws服务的默认端口为3000,但是一般地,与ws服务建立握手时,不应该与ws服务直接进行握手,而是应该通过web代理主机的代理中间件进行握手,所以如果开发者使用ws服务,必须要在web代理主机安装Silky.WebSocket.Middleware

ws服务的创建与通用代理主机的创建一致,只需要将启动模块继承的基类修改为WebSocketHostModule即可。

ws服务的定义如下:

  1. public class WsTestAppService : WsAppServiceBase, IWsTestAppService
  2. {
  3. public async Task Echo(string businessId, string msg)
  4. {
  5. if (BusinessSessionIds.TryGetValue(businessId, out var sessionIds))
  6. {
  7. foreach (var sessionId in sessionIds)
  8. {
  9. SessionManager.SendTo($"message:{msg},sessionId:{sessionId}", sessionId);
  10. }
  11. }
  12. else
  13. {
  14. throw new BusinessException($"不存在businessId为{businessId}的会话");
  15. }
  16. }
  17. }

需要注意的时,在建立握手过程中,必须要指定hashkey从而保证每次回话的微服务实例都是同一个,更多关于ws服务请查看

silky微服务使用拦截器和filter实现了TCC分布式事务,在tcc分布式事务过程中,将事务参与者的调用参数作为undolog日志保存到数据仓库中(当前实现了redis作为undo日志的数据存储器),并在后台执行作业检查分布式事务的执行情况,从而保证数据的最终一致性。

  1. 在应用接口中通过[Transaction]特性进行标识该接口是一个分布式应用方法。
  1. [Transaction]
  2. Task<GetOrderOutput> Create(CreateOrderInput input);
  1. 应用服务实现通过[TccTransaction]特性标识,并指定ConfirmMethod方法和CancelMethod,指定实现的ConfirmMethod方法和CancelMethod必须为public,方法参数与应用实现方法的保持一致。try方法如果需要向ConfirmMethod方法和CancelMethod传递参数通过RpcContext.Context进行。
  1. [TccTransaction(ConfirmMethod = "OrderCreateConfirm", CancelMethod = "OrderCreateCancel")]
  2. [UnitOfWork]
  3. public async Task<GetOrderOutput> Create(CreateOrderInput input)
  4. {
  5. var orderOutput = await _orderDomainService.Create(input);
  6. return orderOutput;
  7. }
  8. [UnitOfWork]
  9. public async Task<GetOrderOutput> OrderCreateConfirm(CreateOrderInput input)
  10. {
  11. var orderId = RpcContext.Context.GetAttachment("orderId");
  12. var order = await _orderDomainService.GetById(orderId.To<long>());
  13. order.Status = OrderStatus.Payed;
  14. order.UpdateTime = DateTime.Now;
  15. order = await _orderDomainService.Update(order);
  16. return order.Adapt<GetOrderOutput>();
  17. }
  18. [UnitOfWork]
  19. public async Task OrderCreateCancel(CreateOrderInput input)
  20. {
  21. var orderId = RpcContext.Context.GetAttachment("orderId");
  22. if (orderId != null)
  23. {
  24. // await _orderDomainService.Delete(orderId.To<long>());
  25. var order = await _orderDomainService.GetById(orderId.To<long>());
  26. order.Status = OrderStatus.UnPay;
  27. await _orderDomainService.Update(order);
  28. }
  29. }

silky的服务定义非常简单,在这里的服务指的是应用服务,与传统MVC的Controller的概念一致。

您只需要在一个业务微服务应用中,新增应用接口层,一般地,我们可以命名为Project.IApplication或是Project.Application.Contracts,并新增应用接口,在应用接口中通过[ServiceRoute]特性进行标识,并在Project.Application项目中实现该接口。

您可以通过[ServiceRoute]指定该应用服务的路由模板, 以及是否允许多个实现。

例如:

  1. namespace Silky.Account.Application.Contracts.Accounts
  2. {
  3. /// <summary>
  4. /// 账号服务
  5. /// </summary>
  6. [ServiceRoute]
  7. public interface IAccountAppService
  8. {
  9. /// <summary>
  10. /// 新增账号
  11. /// </summary>
  12. /// <param name="input">账号信息</param>
  13. /// <returns></returns>
  14. Task<GetAccountOutput> Create(CreateAccountInput input);
  15. }
  16. }

在应用层中实现该接口:

  1. namespace Silky.Account.Application.Accounts
  2. {
  3. public class AccountAppService : IAccountAppService
  4. {
  5. private readonly IAccountDomainService _accountDomainService;
  6. public AccountAppService(IAccountDomainService accountDomainService)
  7. {
  8. _accountDomainService = accountDomainService;
  9. }
  10. public async Task<GetAccountOutput> Create(CreateAccountInput input)
  11. {
  12. var account = await _accountDomainService.Create(input);
  13. return account.Adapt<GetAccountOutput>();
  14. }
  15. }
  16. }

应用接口可以被其他微服务应用或是被网关应用引用。其他微服务可以通过应用接口生成代理,并通过内部实现的rpc框架与该微服务进行通信。silky的rpc通信支持tcc方式的分布式事务,详情见上节。

应用接口被网关引用,web host主机可以通过该应用服务接口生成相应的webapi,并可以生成swagger在线文档。通过http请求,从而实现服务与集群外部进行通信,当http请求到达webhost主机后,silky中间件通过webapi和请求方法路由到服务条目,然后通过内部实现的rpc通信与微服务应用进行通信。

RPC的过滤器: rpc通信支持两种类型的过滤器,在客户端发起请求过程中,会依次调用开发者定义的IClientFilter过滤器,服务端收到请求后,会依次调用IServerFilter然后再执行应用方法本身。

RpcContext: 可以通过RpcContext.Context添加或是获取本次rpc调用的Attachments参数。当然,开发者也可以通过注入IRpcContextAccessor获取本次通信的上线文参数RpcContext

获取当前登录用户: 开发者可以通过NullSession.Instance获取当前登录用户,如果您已经登录系统,那么通过该接口可以获取到当前登录用户的userIduserName等信息。

针对每个服务条目(应用服务接口方法),都实现了服务治理,开发者可以通过governance或是[Governance()]特性对服务的最大并发量、负载均衡算法、执行超时时间、是否使用缓存拦截、失败回调接口、接口是否对外网屏蔽等等属性进行配置。

以下描述了以服务条目为治理单位的属性表单:

属性 说明 缺省值 备注
AddressSelectorMode 负载均衡策略 Polling(轮询) 负载均衡算法支持:Polling(轮询)、Random(随机)、HashAlgorithm(哈希一致性,根据rpc参数的第一个参数值)
ExecutionTimeout 执行超时时间 3000(ms) 单位为(ms),超时时发生熔断,-1表示在rpc通信过程中不会超时
CacheEnabled 是否启用缓存拦截 true rpc通信中是否启用缓存拦截
MaxConcurrent 允许的最大并发量 100
FuseProtection 是否开启熔断保护 true
FuseSleepDuration 熔断休眠时长 60(s) 发生熔断后,多少时长后再次重试该服务实例
FuseTimes 服务提供者允许的熔断次数 3 服务实例连续n次发生熔断端,服务实例将被标识为不健康
FailoverCount 故障转移次数 0 rpc通信异常情况下,允许的重新路由服务实例的次数,0表示有几个服务实例就转移几次
ProhibitExtranet 是否禁止外网访问 false 该属性只允许通过GovernanceAttribute特性进行设置
FallBackType 失败回调指定的类型 null 类型为Type,如果指定了失败回调类型,那么在服务执行失败,则会执行该类型的Invoke方法,该类型,必须要继承IFallbackInvoker该接口

开发者还可以通过[Governance()]特性对某个服务方法进行标识,被该特性标识的治理属性将覆盖微服务的配置/缺省值。

为提高应用的响应,silky支持缓存拦截。缓存拦截在应用服务接口方法上通过缓存拦截特性进行设置,在silky框架中,存在如下三中类型的缓存特性,分别对数据缓存进行新增、更新、删除。

  1. 设置缓存特性–GetCachingInterceptAttribute

  2. 更新缓存特性–UpdateCachingInterceptAttribute

  3. 删除缓存特性–RemoveCachingInterceptAttribute

使用缓存拦截,必须要保证缓存一致性。在rpc通信过程中,使用缓存拦截,同一数据的缓存依据可能会不同(设置的KeyTemplate,例如:缓存依据可能会根据IdNameCode分别进行缓存),从而产生不同的缓存数据,但是在对数据进行更新、删除操作时,由于无法通过RemoveCachingInterceptAttribute特性一次性删除该类型数据的所有缓存数据,这个时候,在实现业务代码过程中,就需要通过分布式缓存接口IDistributedCache<T>实现缓存数据的更新、删除操作。

silky使用zookeeper作为默认服务的注册中心。当前还未扩展支持其他的服务注册中心。

silky支持为微服务集群配置多个服务注册中心,您只需要在配置服务注册中心的链接字符串registrycenter:connectionStrings中,使用分号;就可以指定微服务框架的多个服务注册中心。

为微服务配置服务注册中心如下所示:

  1. registrycenter: // 服务注册中心配置节点
  2. connectionStrings: 127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183;127.0.0.1:2184,127.0.0.1:2185,127.0.0.1:2186 // 服务配置中心链接
  3. registryCenterType: Zookeeper // 注册中心类型
  4. connectionTimeout: 1000 // 链接超时时间(单位:ms)
  5. sessionTimeout: 2000 // 会话超时时间(单位:ms)
  6. operatingTimeout: 4000 // 操作超时时间(单位:ms)
  7. routePath: /services/serviceroutes

silky框架存在两种类型的模块:

  1. 开发者通过继承SilkyModule就可以定义一个普通模块类;
  2. 也可以通过继承StartUpModule定义一个服务注册启动模块类;开发者也可以通过继承StartUpModule,选择合适的依赖包,实现自己的代理主机。

模块的依赖关系: silky框架的模块通过DependsOn特性指定模块的依赖关系,silky框架支持通过直接或是间接的依赖模块。

  1. 通过继承依赖注入标识接口实现服务的注册(推荐)
    silky框架提供了三个依赖注册的相关标识接口:ISingletonDependency(单例模式)、IScopedDependency(区域模式)、ITransientDependency(瞬态模式)。在微服务应用启动时,会扫描继承了这些标识接口的类(服务),并将其自身和继承的接口注册到Ioc容器中。

  2. 定义模块,并在模块中通过RegisterServices()方法的ContainerBuilder注册服务(autofac),或是通过ConfigureServices()方法的IServiceCollection注册服务(微软官方自带的ioc容器)

  3. 通过继承IConfigureService或是ISilkyStartup,通过Configure()方法的IServiceCollection注册服务

Silky因为支持通过IServiceCollection进行服务注册,所以可以很方便的与第三方服务(组件)进行整合,例如:CAP或是MassTransit等分布式事件框架。

silky框架提供了serilog作为日志记录器。只需要在构建主机时,增加UseSerilogDefault(),并添加Serilog相关配置即可。

代码:

  1. public static async Task Main(string[] args)
  2. {
  3. await CreateHostBuilder(args).Build().RunAsync();
  4. }
  5. private static IHostBuilder CreateHostBuilder(string[] args)
  6. {
  7. var hostBuilder = Host.CreateDefaultBuilder(args)
  8. .RegisterSilkyServices<OrderHostModule>()
  9. .UseSerilogDefault();
  10. return hostBuilder;
  11. }

配置:

  1. serilog:
  2. minimumLevel:
  3. default: Information
  4. override:
  5. Microsoft: Warning
  6. Microsoft.Hosting.Lifetime: Information
  7. Silky: Debug
  8. writeTo:
  9. - name: File
  10. args:
  11. path: "./logs/log-.log"
  12. rollingInterval: Day
  13. - name: Console
  14. args:
  15. outputTemplate: "[{Timestamp:yyyy/MM/dd HH:mm:ss} {Level:u11}] {Message:lj} {NewLine}{Exception}{NewLine}"
  16. theme: "Serilog.Sinks.SystemConsole.Themes.SystemConsoleTheme::Literate, Serilog.Sinks.Console"

要求必须在web主机项目(一般为网关项目)安装Silky.Http.MiniProfiler包,并将swaggerDocument:injectMiniProfiler配置项的属性设置为true

  1. swaggerDocument:
  2. injectMiniProfiler: true

image

要求微服务在启动模块依赖SilkySkyApmAgentModule模块,并配置skyWalking相关属性。

  1. [DependsOn(typeof(SilkySkyApmAgentModule))]
  2. public class AccountHostModule : GeneralHostModule
  3. {
  4. }
  1. skyWalking:
  2. serviceName: AccountHost
  3. headerVersions:
  4. - sw8
  5. sampling:
  6. samplePer3Secs: -1
  7. percentage: -1.0
  8. logging:
  9. level: Debug
  10. filePath: "logs/skyapm-{Date}.log"
  11. transport:
  12. interval: 3000
  13. protocolVersion: v8
  14. queueSize: 30000
  15. batchSize: 3000
  16. gRPC:
  17. servers: "127.0.0.1:11800"
  18. timeout: 10000
  19. connectTimeout: 10000
  20. reportTimeout: 600000

在silky的实例项目中,提供了skyWalking通过docker-compose快速启动的服务编排文件samples\docker-compose\infrastr\docker-compose.skywalking.yml,开发者只需要进入到samples\docker-compose\infrastr目录中,通过如下命令即可开始的启动一个skyWalking服务。

  1. cd samples\docker-compose\infrastr
  2. docker-compose -f docker-compose.skywalking.yml

打开http://127.0.0.1:8180即可看到微服务集群的运行情况:

网络拓扑图:

image

链路跟踪:

image

仪表盘:

image

必要前提是开发者已经部署了一套Apollo服务。开发者可以参考Apollo部署节点,部署一套Apollo服务。

在开发过程中,更简单的做法是使用silky实例项目中使用docker-compose已经编排好的文件 docker-compose.apollo.yml

进入到samples\docker-compose\infrastr目录,将.env设置的环境变量EUREKA_INSTANCE_IP_ADDRESS修改为您当前本机的IP地址,不允许为127.0.0.1

运行如下命令,等待1~2分钟即可启动apollo配置服务。

  1. docker-compose -f docker-compose.apollo.yml up -d
  1. 在主机项目通过nuget安装Silky.Apollo包。(这是一个空包,您也可以直接安装Com.Ctrip.Framework.Apollo.AspNetCoreHostingCom.Ctrip.Framework.Apollo.Configuration包)

  2. 在服务注册时,添加对Appo服务配置中心的支持

  1. private static IHostBuilder CreateHostBuilder(string[] args)
  2. {
  3. return Host.CreateDefaultBuilder(args)
  4. .RegisterSilkyServices<AccountHostModule>()
  5. .AddApollo();
  6. }

如果您您想在指定的运行环境中使用Apollo作为微服务的配置中心,而在另外其他运行环境中使用本地配置,那么您也可以通过如下当时处理:

  1. private static IHostBuilder CreateHostBuilder(string[] args)
  2. {
  3. var hostBuilder = Host.CreateDefaultBuilder(args)
  4. .RegisterSilkyServices<AccountHostModule>()
  5. .UseSerilogDefault();
  6. if (EngineContext.Current.IsEnvironment("Apollo"))
  7. {
  8. hostBuilder.AddApollo();
  9. }
  10. return hostBuilder;
  11. }

备注
运行环境您可以通过修改Properties\launchSettings.jsonDOTNET_ENVIRONMENT变量(本地开发模式)
或是通过.env环境变量文件指定DOTNET_ENVIRONMENT变量(docker-compose开发模式)

  1. 在Apollo服务配置中心新建相关的应用,并新增相关的配置

打开地址:http://127.0.0.1:8070 (Applo服务的web管理工具:portal),新建相关的应用。如下图:

image

为应用添加相应的配置:

image

普通业务微服务的配置如下:

  1. # Application
  2. rpc:port = 2201
  3. connectionStrings:default = server=127.0.0.1;port=3306;database=order;uid=root;pwd=qwe!P4ss;
  4. jwtSettings:secret = jv1PZkwjLVCEygM7faLLvEhDGWmFqRUW
  5. # TEST1.silky.sample
  6. registrycenter:registryCenterType = Zookeeper
  7. registrycenter:connectionStrings = 127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183;127.0.0.1:2184,127.0.0.1:2185,127.0.0.1:2186
  8. distributedCache:redis:isEnabled = true
  9. distributedCache:redis:configuration = 127.0.0.1:6379,defaultDatabase=0
  10. rpc:token = ypjdYOzNd4FwENJiEARMLWwK0v7QUHPW
  11. governance:executionTimeout = -1
  12. cap:rabbitmq:hostName = 127.0.0.1
  13. cap:rabbitmq:userName = rabbitmq
  14. cap:rabbitmq:password = rabbitmq

web网关的配置如下:

  1. # TEST1.silky.sample.gateway
  2. gateway:injectMiniProfiler = true
  3. gateway:enableSwaggerDoc = true
  4. gateway:wrapResult = true
  5. gateway:jwtSecret = jaoaNPA1fo1rcPfK23iNufsQKkhTy8eh
  6. swaggerDocument:organizationMode = Group
  7. swaggerDocument:injectMiniProfiler = true
  8. swaggerDocument:termsOfService = https://www.github.com/liuhll/silky
  9. # TEST1.silky.sample
  10. registrycenter:registryCenterType = Zookeeper
  11. registrycenter:connectionStrings = 127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183;127.0.0.1:2184,127.0.0.1:2185,127.0.0.1:2186
  12. distributedCache:redis:isEnabled = true
  13. distributedCache:redis:configuration = 127.0.0.1:6379,defaultDatabase=0
  14. rpc:token = ypjdYOzNd4FwENJiEARMLWwK0v7QUHPW
  15. governance:executionTimeout = -1
  1. 增加Apollo配置中心相关配置(默认读取appsettings.yml),如果指定运行环境变量则读取appsettings.{Environment}.yml中的配置

例如:

  1. apollo:
  2. appId: "silky-stock-host"
  3. cluster: default
  4. metaServer: "http://127.0.0.1:8080/"
  5. # secret: "ffd9d01130ee4329875ac3441c0bedda"
  6. namespaces:
  7. - application
  8. - TEST1.silky.sample
  9. env: DEV
  10. meta:
  11. DEV: "http://127.0.0.1:8080/"
  12. PRO: "http://127.0.0.1:8080/"

silky使用DistributedLock作为分布式锁,在服务路由注册和分布式事务作业中均使用了分布式锁.

silky身份认证与授权通过包Silky.Http.Identity,通过webhost在网关实现统一的身份认证和授权。

silky通过Silky.Jwt包提供的IJwtTokenGenerator实现jwt格式的token。签发token的微服务应用需要通过nuget安装Silky.Jwt包,并在启动模块中依赖JwtModule模块。开发者可以对签发的token的密钥、token有效期、Jwt签名算法、签发者、受众等属性通过配置节点jwtSettings进行配置。开发者至少需要对jwtSettings:secret进行配置。

配置如下:

  1. jwtSettings:
  2. secret: jv1PZkwjLVCEygM7faLLvEhDGWmFqRUW

用户登陆接口如下:

  1. public async Task<string> Login(LoginInput input)
  2. {
  3. var userInfo = await _accountRepository.FirstOrDefaultAsync(p => p.UserName == input.Account
  4. || p.Email == input.Account);
  5. if (userInfo == null)
  6. {
  7. throw new AuthenticationException($"不存在账号为{input.Account}的用户");
  8. }
  9. if (!userInfo.Password.Equals(_passwordHelper.EncryptPassword(userInfo.UserName, input.Password)))
  10. {
  11. throw new AuthenticationException("密码不正确");
  12. }
  13. var payload = new Dictionary<string, object>()
  14. {
  15. { ClaimTypes.UserId, userInfo.Id },
  16. { ClaimTypes.UserName, userInfo.UserName },
  17. { ClaimTypes.Email, userInfo.Email },
  18. };
  19. return _jwtTokenGenerator.Generate(payload);
  20. }
  1. 网关项目(WebHost)的启动模块需要依赖IdentityModule模块
  1. [DependsOn(typeof(IdentityModule))]
  2. public class GatewayHostModule : WebHostModule
  3. {
  4. }
  1. gateway:jwtSecret配置的属性必须与签发token的微服务应用配置的属性jwtSettings:secret的值保持一致。
  1. gateway:
  2. jwtSecret: jv1PZkwjLVCEygM7faLLvEhDGWmFqRUW
  1. 匿名访问

开发者只需要在应用接口或是应用接口方法中标注[AllowAnonymous]特性即可,这样无需用户登陆,也可以访问该接口。

  1. [AllowAnonymous]
  2. Task<string> Login(LoginInput input);

开发者可以在网关应用通过继承SilkyAuthorizationHandler基类,并重写PipelineAsync方法即可实现对自定义授权。

  1. public class TestAuthorizationHandler : SilkyAuthorizationHandler
  2. {
  3. private readonly ILogger<TestAuthorizationHandler> _logger;
  4. private readonly IAuthorizationAppService _authorizationAppService;
  5. public TestAuthorizationHandler(ILogger<TestAuthorizationHandler> logger,
  6. IAuthorizationAppService authorizationAppService)
  7. {
  8. _logger = logger;
  9. _authorizationAppService = authorizationAppService;
  10. }
  11. public async override Task<bool> PipelineAsync(AuthorizationHandlerContext context,
  12. DefaultHttpContext httpContext)
  13. {
  14. // 获取访问的服务条目
  15. var serviceEntry = httpContext.GetServiceEntry();
  16. // 可以通过rpc调用IdentifyApp,实现自定义的授权
  17. return _authorizationAppService.Authorization(sserviceEntry.ServiceDescriptor.Id);
  18. }
  19. }

silky实现了基于AutoMapperMapster的对象属性映射的包。实现的代理主机默认依赖MapsterModule包,使用Mapster作为对象映射的组件。

只需要通过Adapt方法即可实现对象属性映射。

efcore数据访问组件主要参考了furion的实现。提供了数据仓库、数据库定位器、多租户等实现方式。使用方式与其基本保持一致。

github: https://github.com/liuhll/silky

gitee: https://gitee.com/liuhll2/silky

开发者文档: http://docs.silky-fk.com/

版权声明:本文为bea084100123原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/bea084100123/p/15135106.html