找回密码
 立即注册
首页 业界区 业界 Admin.NET开源版微服务改造记录

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

济曝喊 7 天前
Admin.NET开源版微服务改造记录

将Admin.NET.Core项目拆分成两个项目:Admin.NET.Common,Admin.NET.Core

Admin.NET.Common放基础工具类
Admin.NET.Core放框架核心类库
AspireApp.AppHost中的AppHost.cs配置:
  1. using Aspire.Hosting;
  2. using Aspire.Hosting.Dapr;
  3. using AspireApp.AppHost;
  4. var builder = DistributedApplication.CreateBuilder(args);
  5. var postgresQL = builder.AddPostgres("postgresQL")
  6.                         .WithImage("ankane/pgvector")
  7.                         .WithImageTag("latest")
  8.                         .WithLifetime(ContainerLifetime.Persistent)
  9.                         .WithHealthCheck()
  10.                         .WithPgWeb();
  11. var postgres = postgresQL.AddDatabase("postgres");
  12. var postgres2 = postgresQL.AddDatabase("postgres2");
  13. //var redis = builder.AddRedis("redis").WithLifetime(ContainerLifetime.Persistent)
  14. //                    .WithHealthCheck()
  15. //                    .WithRedisCommander();
  16. // 使用 RabbitMQ 作为 Pub/Sub 组件
  17. //var rabbitmq = builder.AddRabbitMQ("rabbitmq")
  18. //                        .WithLifetime(ContainerLifetime.Persistent)
  19. //                        .WithHealthCheck()
  20. //                        .WithManagementPlugin();
  21. // 1. 定义共享目录的绝对路径(建议指向 admin-net-core 的实际目录或独立的 shared 目录)
  22. var uploadPath = Path.GetFullPath("../Admin.NET/Admin.NET.Core/wwwroot/upload");
  23. // 确保目录存在
  24. if (!Directory.Exists(uploadPath))
  25. {
  26.     Directory.CreateDirectory(uploadPath);
  27. }
  28. // Admin.NET.Core 使用 Furion 的 Knife4j UI,不使用 Aspire 的 Swagger UI
  29. var core = builder.AddProject<Projects.Admin_NET_Core>("admin-net-core")
  30.     .WithReference(postgres)
  31.     .WaitFor(postgres)
  32.     .WithSwaggerUI();
  33. var baseApi = builder.AddProject<Projects.Base>("base")
  34.     .WithReference(postgres2)
  35.     .WithSwaggerUI()
  36.     .WithReference(core)
  37.     .WaitFor(postgres2)
  38.     .WaitFor(core);
  39. var yarp = builder.AddProject<Projects.AspireApp_Yarp>("aspireapp-yarp")
  40.     .WithEndpoint( port: 5008, scheme: "http", name: "yarp-http")    // 指定唯一名称
  41.     .WithEndpoint( port: 7008, scheme: "https", name: "yarp-https") // 指定唯一名称
  42.     .WithReference(core)
  43.     .WithReference(baseApi)
  44.     .WaitFor(core)
  45.     .WaitFor(baseApi);
  46. //var frontend = builder.AddNodeApp(
  47. //       "frontend",
  48. //       scriptPath: "scripts/run-pnpm.cjs",
  49. //       workingDirectory: "../Web",
  50. //       args: new[] { "dev" }
  51. //   )
  52. //   .WithReference(yarp)
  53. //   .WaitFor(yarp);
  54. builder.Build().Run();
复制代码
AIP网关:AspireApp.Yarp

Program.cs
  1. var builder = WebApplication.CreateBuilder(args);
  2. builder.AddServiceDefaults();
  3. builder.Services.AddReverseProxy()
  4.                 .LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"))
  5.                 .AddServiceDiscoveryDestinationResolver();
  6. var app = builder.Build();
  7. app.MapDefaultEndpoints();
  8. app.MapReverseProxy();
  9. app.MapGet("/", () => "Hello World!");
  10. app.Run();
复制代码
appsettings.json
  1. {
  2.   "Logging": {
  3.     "LogLevel": {
  4.       "Default": "Information",
  5.       "Microsoft.AspNetCore": "Warning"
  6.     }
  7.   },
  8.   "AllowedHosts": "*",
  9.   "ReverseProxy": {
  10.     "Routes": {
  11.       "core": {
  12.         "ClusterId": "core",
  13.         "Match": {
  14.           "Path": "/core/{**remainder}"
  15.         },
  16.         "Transforms": [
  17.           { "PathRemovePrefix": "/core" },
  18.           { "PathPrefix": "/" },
  19.           { "RequestHeaderOriginalHost": "true" }
  20.         ]
  21.       },
  22.       "base": {
  23.         "ClusterId": "base",
  24.         "Match": {
  25.           "Path": "/base/{**remainder}"
  26.         },
  27.         "Transforms": [
  28.           { "PathRemovePrefix": "/base" },
  29.           { "PathPrefix": "/" },
  30.           { "RequestHeaderOriginalHost": "true" }
  31.         ]
  32.       }
  33.     },
  34.     "Clusters": {
  35.       "core": {
  36.         "Destinations": {
  37.           "base_destination": {
  38.             "Address": "http+https://admin-net-core"
  39.           }
  40.         }
  41.       },
  42.       "base": {
  43.         "Destinations": {
  44.           "base_destination": {
  45.             "Address": "http+https://base"
  46.           }
  47.         }
  48.       }
  49.     }
  50.   }
  51. }
复制代码
业务项目(base项目)调用核心项目(core项目)的方法

我们使用Refit来服务调用
在base项目中的Startup.cs中
  1.         // 注册 JwtTokenHandler - 用于自动添加 JWT Token 到 Refit 请求
  2.         services.AddTransient<JwtTokenHandler>();
  3.         
  4.         // 配置 Refit 客户端并添加 JWT Token 处理器
  5.         //系统配置
  6.         services.AddRefitClient<IConfigService>(refitSettings)
  7.                .ConfigureHttpClient(c => c.BaseAddress = new("https+http://admin-net-core"))
  8.                .AddHttpMessageHandler<JwtTokenHandler>();
  9.         //系统菜单     
  10.         services.AddRefitClient<IMenuService>(refitSettings)
  11.                .ConfigureHttpClient(c => c.BaseAddress = new("https+http://admin-net-core"))
  12.                .AddHttpMessageHandler<JwtTokenHandler>();
  13.         //组织机构
  14.         services.AddRefitClient<IOrgService>(refitSettings)
  15.                .ConfigureHttpClient(c => c.BaseAddress = new("https+http://admin-net-core"))
  16.                .AddHttpMessageHandler<JwtTokenHandler>();
  17.         //文件
  18.         services.AddRefitClient<IFileService>(refitSettings)
  19.                .ConfigureHttpClient(c => c.BaseAddress = new("https+http://admin-net-core"))
  20.                .AddHttpMessageHandler<JwtTokenHandler>();
  21.         services.AddRefitClient<ITest>(refitSettings)
  22.             .ConfigureHttpClient(c => c.BaseAddress = new("https+http://apiservice"))
  23.             .AddHttpMessageHandler<JwtTokenHandler>();
复制代码
其中最重要的权限接口调用
  1. using Refit;
  2. using GetAttribute = Refit.GetAttribute;
  3. namespace Base.Rest;
  4. public interface IMenuService
  5. {
  6.     [Get("/api/sysMenu/getOwnBtnPermList")]
  7.     Task<List<string>> GetOwnBtnPermList();
  8.     [Get("/api/sysMenu/getAllBtnPermList")]
  9.     Task<List<string>> GetAllBtnPermList();
  10. }
复制代码
修改base项目的权限验证方法JwtHandler.cs
IConfigService  IMenuService 就是我们定义的Refit接口,这样,每次权限验证就会调用core项目的API接口
  1. using Admin.NET.Core;
  2. using Admin.NET.Core.Service;
  3. using Base.Rest;
  4. using Furion;
  5. using Furion.Authorization;
  6. using Furion.DataEncryption;
  7. using Microsoft.AspNetCore.Authorization;
  8. using Microsoft.AspNetCore.Http;
  9. using System;
  10. using System.Threading.Tasks;
  11. namespace Admin.NET.Application;
  12. public class JwtHandler : AppAuthorizeHandler
  13. {
  14.     private readonly SysCacheService _sysCacheService = App.GetRequiredService<SysCacheService>();
  15.     private readonly IConfigService _sysConfigService = App.GetRequiredService<IConfigService>();
  16.     private static readonly IMenuService SysMenuService = App.GetRequiredService<IMenuService>();
  17.     /// <summary>
  18.     /// 自动刷新Token
  19.     /// </summary>
  20.     /// <param name="context"></param>
  21.     /// <param name="httpContext"></param>
  22.     /// <returns></returns>
  23.     public override async Task HandleAsync(AuthorizationHandlerContext context, DefaultHttpContext httpContext)
  24.     {
  25.         // 若当前账号存在黑名单中则授权失败
  26.         if (_sysCacheService.ExistKey($"{CacheConst.KeyBlacklist}{context.User.FindFirst(ClaimConst.UserId)?.Value}"))
  27.         {
  28.             context.Fail();
  29.             context.GetCurrentHttpContext().SignoutToSwagger();
  30.             return;
  31.         }
  32.         var tokenExpire = await _sysConfigService.GetTokenExpire();
  33.         var refreshTokenExpire = await _sysConfigService.GetRefreshTokenExpire();
  34.         if (JWTEncryption.AutoRefreshToken(context, context.GetCurrentHttpContext(), tokenExpire.Result, refreshTokenExpire.Result))
  35.         {
  36.             await AuthorizeHandleAsync(context);
  37.         }
  38.         else
  39.         {
  40.             context.Fail(); // 授权失败
  41.             var currentHttpContext = context.GetCurrentHttpContext();
  42.             if (currentHttpContext == null) return;
  43.             // 跳过由于 SignatureAuthentication 引发的失败
  44.             if (currentHttpContext.Items.ContainsKey(SignatureAuthenticationDefaults.AuthenticateFailMsgKey)) return;
  45.             currentHttpContext.SignoutToSwagger();
  46.         }
  47.     }
  48.     public override async Task<bool> PipelineAsync(AuthorizationHandlerContext context, DefaultHttpContext httpContext)
  49.     {
  50.         // 已自动验证 Jwt Token 有效性
  51.         return await CheckAuthorizeAsync(httpContext);
  52.     }
  53.     /// <summary>
  54.     /// 权限校验核心逻辑
  55.     /// </summary>
  56.     /// <param name="httpContext"></param>
  57.     /// <returns></returns>
  58.     private static async Task<bool> CheckAuthorizeAsync(DefaultHttpContext httpContext)
  59.     {
  60.         // 登录模式判断PC、APP
  61.         if (App.User.FindFirst(ClaimConst.LoginMode)?.Value == ((int)LoginModeEnum.APP).ToString())
  62.             return true;
  63.         // 排除超管
  64.         if (App.User.FindFirst(ClaimConst.AccountType)?.Value == ((int)AccountTypeEnum.SuperAdmin).ToString())
  65.             return true;
  66.         // 路由名称
  67.         var routeName = httpContext.Request.Path.StartsWithSegments("/api")
  68.             ? httpContext.Request.Path.Value![5..].Replace("/", ":")
  69.             : httpContext.Request.Path.Value![1..].Replace("/", ":");
  70.         // 获取用户拥有按钮权限集合
  71.         var ownBtnPermList = await SysMenuService.GetOwnBtnPermList();
  72.         if (ownBtnPermList.Exists(u => routeName.Equals(u, StringComparison.CurrentCultureIgnoreCase)))
  73.             return true;
  74.         // 获取系统所有按钮权限集合
  75.         var allBtnPermList = await SysMenuService.GetAllBtnPermList();
  76.         return allBtnPermList.TrueForAll(u => !routeName.Equals(u, StringComparison.CurrentCultureIgnoreCase));
  77.     }
  78. }
复制代码
项目地址

AspireApp: Admin.NET微服务版

Admin.NET:
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册