Admin.NET开源版微服务改造记录

张开发
2026/4/9 15:04:10 15 分钟阅读

分享文章

Admin.NET开源版微服务改造记录
Admin.NET开源版微服务改造记录将Admin.NET.Core项目拆分成两个项目Admin.NET.CommonAdmin.NET.CoreAdmin.NET.Common放基础工具类Admin.NET.Core放框架核心类库AspireApp.AppHost中的AppHost.cs配置using Aspire.Hosting; using Aspire.Hosting.Dapr; using AspireApp.AppHost; var builder DistributedApplication.CreateBuilder(args); var postgresQL builder.AddPostgres(postgresQL) .WithImage(ankane/pgvector) .WithImageTag(latest) .WithLifetime(ContainerLifetime.Persistent) .WithHealthCheck() .WithPgWeb(); var postgres postgresQL.AddDatabase(postgres); var postgres2 postgresQL.AddDatabase(postgres2); //var redis builder.AddRedis(redis).WithLifetime(ContainerLifetime.Persistent) // .WithHealthCheck() // .WithRedisCommander(); // 使用 RabbitMQ 作为 Pub/Sub 组件 //var rabbitmq builder.AddRabbitMQ(rabbitmq) // .WithLifetime(ContainerLifetime.Persistent) // .WithHealthCheck() // .WithManagementPlugin(); // 1. 定义共享目录的绝对路径建议指向 admin-net-core 的实际目录或独立的 shared 目录 var uploadPath Path.GetFullPath(../Admin.NET/Admin.NET.Core/wwwroot/upload); // 确保目录存在 if (!Directory.Exists(uploadPath)) { Directory.CreateDirectory(uploadPath); } // Admin.NET.Core 使用 Furion 的 Knife4j UI不使用 Aspire 的 Swagger UI var core builder.AddProjectProjects.Admin_NET_Core(admin-net-core) .WithReference(postgres) .WaitFor(postgres) .WithSwaggerUI(); var baseApi builder.AddProjectProjects.Base(base) .WithReference(postgres2) .WithSwaggerUI() .WithReference(core) .WaitFor(postgres2) .WaitFor(core); var yarp builder.AddProjectProjects.AspireApp_Yarp(aspireapp-yarp) .WithEndpoint( port: 5008, scheme: http, name: yarp-http) // 指定唯一名称 .WithEndpoint( port: 7008, scheme: https, name: yarp-https) // 指定唯一名称 .WithReference(core) .WithReference(baseApi) .WaitFor(core) .WaitFor(baseApi); //var frontend builder.AddNodeApp( // frontend, // scriptPath: scripts/run-pnpm.cjs, // workingDirectory: ../Web, // args: new[] { dev } // ) // .WithReference(yarp) // .WaitFor(yarp); builder.Build().Run();AIP网关AspireApp.YarpProgram.csvar builder WebApplication.CreateBuilder(args); builder.AddServiceDefaults(); builder.Services.AddReverseProxy() .LoadFromConfig(builder.Configuration.GetSection(ReverseProxy)) .AddServiceDiscoveryDestinationResolver(); var app builder.Build(); app.MapDefaultEndpoints(); app.MapReverseProxy(); app.MapGet(/, () Hello World!); app.Run();appsettings.json{ Logging: { LogLevel: { Default: Information, Microsoft.AspNetCore: Warning } }, AllowedHosts: *, ReverseProxy: { Routes: { core: { ClusterId: core, Match: { Path: /core/{**remainder} }, Transforms: [ { PathRemovePrefix: /core }, { PathPrefix: / }, { RequestHeaderOriginalHost: true } ] }, base: { ClusterId: base, Match: { Path: /base/{**remainder} }, Transforms: [ { PathRemovePrefix: /base }, { PathPrefix: / }, { RequestHeaderOriginalHost: true } ] } }, Clusters: { core: { Destinations: { base_destination: { Address: httphttps://admin-net-core } } }, base: { Destinations: { base_destination: { Address: httphttps://base } } } } } }业务项目(base项目)调用核心项目(core项目的方法我们使用Refit来服务调用在base项目中的Startup.cs中// 注册 JwtTokenHandler - 用于自动添加 JWT Token 到 Refit 请求 services.AddTransientJwtTokenHandler(); // 配置 Refit 客户端并添加 JWT Token 处理器 //系统配置 services.AddRefitClientIConfigService(refitSettings) .ConfigureHttpClient(c c.BaseAddress new(httpshttp://admin-net-core)) .AddHttpMessageHandlerJwtTokenHandler(); //系统菜单 services.AddRefitClientIMenuService(refitSettings) .ConfigureHttpClient(c c.BaseAddress new(httpshttp://admin-net-core)) .AddHttpMessageHandlerJwtTokenHandler(); //组织机构 services.AddRefitClientIOrgService(refitSettings) .ConfigureHttpClient(c c.BaseAddress new(httpshttp://admin-net-core)) .AddHttpMessageHandlerJwtTokenHandler(); //文件 services.AddRefitClientIFileService(refitSettings) .ConfigureHttpClient(c c.BaseAddress new(httpshttp://admin-net-core)) .AddHttpMessageHandlerJwtTokenHandler(); services.AddRefitClientITest(refitSettings) .ConfigureHttpClient(c c.BaseAddress new(httpshttp://apiservice)) .AddHttpMessageHandlerJwtTokenHandler();其中最重要的权限接口调用using Refit; using GetAttribute Refit.GetAttribute; namespace Base.Rest; public interface IMenuService { [Get(/api/sysMenu/getOwnBtnPermList)] TaskListstring GetOwnBtnPermList(); [Get(/api/sysMenu/getAllBtnPermList)] TaskListstring GetAllBtnPermList(); }修改base项目的权限验证方法JwtHandler.csIConfigService IMenuService 就是我们定义的Refit接口这样每次权限验证就会调用core项目的API接口using Admin.NET.Core; using Admin.NET.Core.Service; using Base.Rest; using Furion; using Furion.Authorization; using Furion.DataEncryption; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using System; using System.Threading.Tasks; namespace Admin.NET.Application; public class JwtHandler : AppAuthorizeHandler { private readonly SysCacheService _sysCacheService App.GetRequiredServiceSysCacheService(); private readonly IConfigService _sysConfigService App.GetRequiredServiceIConfigService(); private static readonly IMenuService SysMenuService App.GetRequiredServiceIMenuService(); /// summary /// 自动刷新Token /// /summary /// param namecontext/param /// param namehttpContext/param /// returns/returns public override async Task HandleAsync(AuthorizationHandlerContext context, DefaultHttpContext httpContext) { // 若当前账号存在黑名单中则授权失败 if (_sysCacheService.ExistKey(${CacheConst.KeyBlacklist}{context.User.FindFirst(ClaimConst.UserId)?.Value})) { context.Fail(); context.GetCurrentHttpContext().SignoutToSwagger(); return; } var tokenExpire await _sysConfigService.GetTokenExpire(); var refreshTokenExpire await _sysConfigService.GetRefreshTokenExpire(); if (JWTEncryption.AutoRefreshToken(context, context.GetCurrentHttpContext(), tokenExpire.Result, refreshTokenExpire.Result)) { await AuthorizeHandleAsync(context); } else { context.Fail(); // 授权失败 var currentHttpContext context.GetCurrentHttpContext(); if (currentHttpContext null) return; // 跳过由于 SignatureAuthentication 引发的失败 if (currentHttpContext.Items.ContainsKey(SignatureAuthenticationDefaults.AuthenticateFailMsgKey)) return; currentHttpContext.SignoutToSwagger(); } } public override async Taskbool PipelineAsync(AuthorizationHandlerContext context, DefaultHttpContext httpContext) { // 已自动验证 Jwt Token 有效性 return await CheckAuthorizeAsync(httpContext); } /// summary /// 权限校验核心逻辑 /// /summary /// param namehttpContext/param /// returns/returns private static async Taskbool CheckAuthorizeAsync(DefaultHttpContext httpContext) { // 登录模式判断PC、APP if (App.User.FindFirst(ClaimConst.LoginMode)?.Value ((int)LoginModeEnum.APP).ToString()) return true; // 排除超管 if (App.User.FindFirst(ClaimConst.AccountType)?.Value ((int)AccountTypeEnum.SuperAdmin).ToString()) return true; // 路由名称 var routeName httpContext.Request.Path.StartsWithSegments(/api) ? httpContext.Request.Path.Value![5..].Replace(/, :) : httpContext.Request.Path.Value![1..].Replace(/, :); // 获取用户拥有按钮权限集合 var ownBtnPermList await SysMenuService.GetOwnBtnPermList(); if (ownBtnPermList.Exists(u routeName.Equals(u, StringComparison.CurrentCultureIgnoreCase))) return true; // 获取系统所有按钮权限集合 var allBtnPermList await SysMenuService.GetAllBtnPermList(); return allBtnPermList.TrueForAll(u !routeName.Equals(u, StringComparison.CurrentCultureIgnoreCase)); } }

更多文章