chore: upgrade all projects to .NET 10.0 and latest packages

This commit is contained in:
Sam 2026-02-02 01:04:51 +08:00
parent 22ab0214e6
commit e51ea08c8f
8 changed files with 362 additions and 19 deletions

View File

@ -0,0 +1,157 @@
# Fengling.Console 运管中心规划
## 项目概述
**项目名称**: Fengling.Console
**中文名称**: 风铃运管中心
**定位**: 统一运维管理平台
## 架构整合
### 1. 后端整合
- **原项目**: `src/YarpGateway/` (YARP Gateway)
- **整合到**: `src/Fengling.Console/` (新建)
- **新增功能**: OAuth Client管理
### 2. 前端整合
- **原项目**: `src/YarpGateway.Admin/` (Vue 3 + Vite)
- **整合到**: `src/Fengling.Console.Web/` (新建)
- **功能扩展**:
- 网关路由管理
- 租户管理
- OAuth Client管理
- 用户管理通过AuthService API
## 功能模块
### 模块1: 网关管理
- 租户列表
- 租户路由配置
- 集群实例管理
- 全局路由配置
- 负载均衡策略
### 模块2: OAuth Client管理
- Client ID/Secret管理
- 重定向URI配置
- 授权类型配置
- Scope配置
- Client状态管理
### 模块3: 用户管理
- 用户列表
- 用户角色分配
- 租户分配
- 用户状态管理
## 认证集成
### Fengling.Console作为OAuth Client
需要在AuthService初始化时注册
```csharp
// Client配置
ClientId: "fengling-console"
ClientSecret: "console-secret-xxx"
RedirectUris: ["http://console.fengling.local/auth/callback"]
PostLogoutRedirectUris: ["http://console.fengling.local/"]
Scopes: ["api", "offline_access"]
GrantTypes: ["authorization_code", "refresh_token"]
```
## 目录结构
```
src/
├── Fengling.AuthService/ # 认证服务(已完成部分)
├── Fengling.Console/ # 运管中心后端(新建)
│ ├── Controllers/
│ │ ├── Gateway/ # 网关管理
│ │ ├── OAuth/ # OAuth Client管理
│ │ └── Users/ # 用户管理代理
│ ├── Services/
│ └── Data/
├── Fengling.Console.Web/ # 运管中心前端(新建)
│ ├── src/
│ │ ├── views/
│ │ │ ├── gateway/ # 网关管理
│ │ │ ├── oauth/ # OAuth管理
│ │ │ └── users/ # 用户管理
│ │ └── components/
│ └── YarpGateway.Admin/ # 原有代码迁移
└── YarpGateway/ # 网关服务(保留)
```
## 技术栈
### 后端 (Fengling.Console)
- .NET 10.0
- ASP.NET Core Web API
- EF Core 10.0
- PostgreSQL
- OpenTelemetry
### 前端 (Fengling.Console.Web)
- Vue 3 + TypeScript
- Vite
- Element Plus
- Pinia
- Vue Router
## 实施计划
### Phase 1: 认证服务扩展
1. [ ] Task 5-9: 完成AuthService基础功能
2. [ ] Task 10: 添加OAuth Client模型和管理
3. [ ] Task 11: 预注册Fengling.Console作为Client
### Phase 2: 运管中心后端
1. [ ] Task 12: 创建Fengling.Console项目
2. [ ] Task 13: 迁移网关管理功能
3. [ ] Task 14: 添加OAuth Client管理API
4. [ ] Task 15: 添加用户管理代理API
### Phase 3: 运管中心前端
1. [ ] Task 16: 创建Fengling.Console.Web项目
2. [ ] Task 17: 迁移YarpGateway.Admin代码
3. [ ] Task 18: 添加OAuth管理界面
4. [ ] Task 19: 集成OAuth认证登录
## 依赖关系
```
Fengling.Console.Web
↓ (OAuth 2.0)
Fengling.Console
↓ (数据库)
PostgreSQL
↓ (路由配置)
YarpGateway
```
## 数据库设计
### OAuth Applications表
```sql
CREATE TABLE oauth_applications (
id BIGSERIAL PRIMARY KEY,
client_id VARCHAR(100) UNIQUE NOT NULL,
client_secret VARCHAR(200),
display_name VARCHAR(100),
redirect_uris TEXT[],
post_logout_redirect_uris TEXT[],
scopes TEXT[],
grant_types TEXT[],
client_type VARCHAR(20),
consent_type VARCHAR(20),
status VARCHAR(20),
created_at TIMESTAMP DEFAULT NOW()
);
```
## 注意事项
1. **向后兼容**: YarpGateway继续独立运行
2. **渐进式迁移**: 先完成Console后端再迁移前端
3. **统一认证**: 所有管理界面通过AuthService OAuth登录
4. **权限控制**: Console内部API也需要认证

View File

@ -24,7 +24,7 @@ Edit: `src/Fengling.AuthService/Fengling.AuthService.csproj`
```xml ```xml
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup> </PropertyGroup>
@ -32,8 +32,8 @@ Edit: `src/Fengling.AuthService/Fengling.AuthService.csproj`
<ItemGroup> <ItemGroup>
<PackageReference Include="OpenIddict.AspNetCore" Version="7.2.0" /> <PackageReference Include="OpenIddict.AspNetCore" Version="7.2.0" />
<PackageReference Include="OpenIddict.EntityFrameworkCore" Version="7.2.0" /> <PackageReference Include="OpenIddict.EntityFrameworkCore" Version="7.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="9.0.1" /> <PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="10.0.1" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.3" /> <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="10.0.3" />
<PackageReference Include="Serilog.AspNetCore" Version="9.0.0" /> <PackageReference Include="Serilog.AspNetCore" Version="9.0.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" /> <PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
<PackageReference Include="OpenTelemetry" Version="1.11.0" /> <PackageReference Include="OpenTelemetry" Version="1.11.0" />
@ -80,14 +80,14 @@ This is the first task of implementing the Fengling Authentication Service. We'r
**Architecture**: ASP.NET Core Web API with OpenIddict for OAuth2/OIDC, PostgreSQL for user data. **Architecture**: ASP.NET Core Web API with OpenIddict for OAuth2/OIDC, PostgreSQL for user data.
**Tech Stack**: .NET 9.0, OpenIddict 7.2.0, EF Core 9.0, PostgreSQL, Serilog 9.0.0, OpenTelemetry 1.11.0. **Tech Stack**: .NET 10.0, OpenIddict 7.2.0, EF Core 10.0, PostgreSQL, Serilog 9.0.0, OpenTelemetry 1.11.0.
**Working Directory**: `/Users/movingsam/Fengling.Refactory.Buiding/src` **Working Directory**: `/Users/movingsam/Fengling.Refactory.Buiding/src`
## Verification ## Verification
- [ ] Project file created successfully - [ ] Project file created successfully
- [ ] Target framework set to net9.0 - [ ] Target framework set to net10.0
- [ ] All NuGet packages added (latest versions) - [ ] All NuGet packages added (latest versions)
- [ ] appsettings.json configured with connection string and OpenIddict settings - [ ] appsettings.json configured with connection string and OpenIddict settings
- [ ] Project builds successfully - [ ] Project builds successfully
@ -97,4 +97,4 @@ This is the first task of implementing the Fengling Authentication Service. We'r
- OpenIddict packages updated to 7.2.0 (latest) - OpenIddict packages updated to 7.2.0 (latest)
- All dependencies updated to latest versions - All dependencies updated to latest versions
- Used .NET 9.0 as target framework - Used .NET 10.0 as target framework

View File

@ -0,0 +1,186 @@
# Task 5: Create OpenIddict Endpoints
## Task Description
**Files:**
- Create: `src/Fengling.AuthService/Controllers/AuthorizationController.cs`
## Implementation Steps
### Step 1: Create authorization endpoints
Create: `src/Fengling.AuthService/Controllers/AuthorizationController.cs`
```csharp
using Fengling.AuthService.Models;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using OpenIddict.Abstractions;
using OpenIddict.Server.AspNetCore;
using static OpenIddict.Abstractions.OpenIddictConstants;
namespace Fengling.AuthService.Controllers;
public class AuthorizationController : Controller
{
private readonly IOpenIddictApplicationManager _applicationManager;
private readonly IOpenIddictAuthorizationManager _authorizationManager;
private readonly IOpenIddictScopeManager _scopeManager;
private readonly SignInManager<ApplicationUser> _signInManager;
private readonly UserManager<ApplicationUser> _userManager;
private readonly ILogger<AuthorizationController> _logger;
public AuthorizationController(
IOpenIddictApplicationManager applicationManager,
IOpenIddictAuthorizationManager authorizationManager,
IOpenIddictScopeManager scopeManager,
SignInManager<ApplicationUser> signInManager,
UserManager<ApplicationUser> userManager,
ILogger<AuthorizationController> logger)
{
_applicationManager = applicationManager;
_authorizationManager = authorizationManager;
_scopeManager = scopeManager;
_signInManager = signInManager;
_userManager = userManager;
_logger = logger;
}
[HttpPost("~/connect/token")]
[Produces("application/json")]
public async Task<IActionResult> Exchange()
{
var request = HttpContext.GetOpenIddictServerRequest() ??
throw new InvalidOperationException("The OpenID Connect request cannot be retrieved.");
if (request.IsPasswordGrantType())
{
var user = await _userManager.FindByNameAsync(request.Username);
if (user == null || user.IsDeleted)
{
return Forbid(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme,
new AuthenticationProperties(new Dictionary<string, string?>
{
[OpenIddictServerAspNetCoreConstants.Properties.Error] = Errors.InvalidGrant,
[OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "用户不存在"
}));
}
var result = await _signInManager.CheckPasswordSignInAsync(user, request.Password, false);
if (!result.Succeeded)
{
return Forbid(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme,
new AuthenticationProperties(new Dictionary<string, string?>
{
[OpenIddictServerAspNetCoreConstants.Properties.Error] = Errors.InvalidGrant,
[OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "用户名或密码错误"
}));
}
var principal = await _signInManager.CreateUserPrincipalAsync(user);
var claims = new List<System.Security.Claims.Claim>
{
new(Claims.Subject, user.Id.ToString()),
new(Claims.Name, user.UserName ?? string.Empty),
new(Claims.Email, user.Email ?? string.Empty),
new("tenant_id", user.TenantId.ToString())
};
var roles = await _userManager.GetRolesAsync(user);
foreach (var role in roles)
{
claims.Add(new Claim(Claims.Role, role));
}
principal.SetScopes(request.GetScopes());
principal.SetResources(await _scopeManager.ListResourcesAsync(principal.GetScopes()).ToListAsync());
return SignIn(principal, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);
}
return Forbid(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme,
new AuthenticationProperties(new Dictionary<string, string?>
{
[OpenIddictServerAspNetCoreConstants.Properties.Error] = Errors.UnsupportedGrantType,
[OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "不支持的授权类型"
}));
}
[HttpGet("~/connect/authorize")]
[HttpPost("~/connect/authorize")]
[IgnoreAntiforgeryToken]
public async Task<IActionResult> Authorize()
{
var request = HttpContext.GetOpenIddictServerRequest() ??
throw new InvalidOperationException("The OpenID Connect request cannot be retrieved.");
var result = await HttpContext.AuthenticateAsync();
if (result == null || !result.Succeeded)
{
return Challenge(
new AuthenticationProperties
{
RedirectUri = Request.Path + Request.QueryString
},
OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);
}
return Ok(new { message = "Authorization endpoint" });
}
[HttpPost("~/connect/logout")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Logout()
{
await HttpContext.SignOutAsync();
return SignOut(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);
}
}
```
### Step 2: Run to verify
Run:
```bash
dotnet run
```
Test with curl:
```bash
curl -X POST http://localhost:5000/connect/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=password" \
-d "username=admin" \
-d "password=Admin@123" \
-d "scope=api offline_access"
```
Expected: 400 error (user doesn't exist yet, but endpoint is working)
### Step 3: Commit
```bash
git add src/Fengling.AuthService/Controllers/AuthorizationController.cs
git commit -m "feat(auth): add OpenIddict authorization endpoints"
```
## Context
This task creates OpenIddict OAuth2/OIDC endpoints including token exchange, authorize, and logout. The token endpoint supports password flow for direct authentication.
**Tech Stack**: OpenIddict 7.2.0, ASP.NET Core
## Verification
- [ ] AuthorizationController created
- [ ] Token endpoint supports password flow
- [ ] Tenant ID added to token claims
- [ ] Build succeeds
- [ ] Committed to git
## Notes
- Token endpoint returns JWT with tenant_id claim
- Logout endpoint clears session

View File

@ -1,21 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.1" /> <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.1" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="7.2.0" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="7.2.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.3"> <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.3">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="OpenIddict.AspNetCore" Version="7.2.0" /> <PackageReference Include="OpenIddict.AspNetCore" Version="7.2.0" />
<PackageReference Include="OpenIddict.EntityFrameworkCore" Version="7.2.0" /> <PackageReference Include="OpenIddict.EntityFrameworkCore" Version="7.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="9.0.1" /> <PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="10.0.1" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.3" /> <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="10.0.3" />
<PackageReference Include="Serilog.AspNetCore" Version="9.0.0" /> <PackageReference Include="Serilog.AspNetCore" Version="9.0.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" /> <PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
<PackageReference Include="OpenTelemetry" Version="1.11.0" /> <PackageReference Include="OpenTelemetry" Version="1.11.0" />

View File

@ -7,16 +7,16 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="10.0.0" /> <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="10.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.0"> <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.3">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles, analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.0" /> <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="10.0.3" />
<PackageReference Include="Serilog.AspNetCore" Version="8.0.0" /> <PackageReference Include="Serilog.AspNetCore" Version="9.0.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" /> <PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" /> <PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
<PackageReference Include="StackExchange.Redis" Version="2.8.16" /> <PackageReference Include="StackExchange.Redis" Version="2.8.24" />
<PackageReference Include="Yarp.ReverseProxy" Version="2.2.0" /> <PackageReference Include="Yarp.ReverseProxy" Version="2.2.0" />
</ItemGroup> </ItemGroup>

View File

@ -13,7 +13,7 @@ using System.Reflection;
[assembly: System.Reflection.AssemblyCompanyAttribute("YarpGateway")] [assembly: System.Reflection.AssemblyCompanyAttribute("YarpGateway")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] [assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+d52b7c9a46ded51a443127feb64c42410418f05e")] [assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")]
[assembly: System.Reflection.AssemblyProductAttribute("YarpGateway")] [assembly: System.Reflection.AssemblyProductAttribute("YarpGateway")]
[assembly: System.Reflection.AssemblyTitleAttribute("YarpGateway")] [assembly: System.Reflection.AssemblyTitleAttribute("YarpGateway")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] [assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]

View File

@ -1 +1 @@
1eeba3ffadd654a1cb0f5a3d5c67778e6f01b8ed8162ae7982a98e3e3c44e84f 8ec52e08f20064638c4db3c23d5adde50628e34c7dcaf8a439956f9b42f760de