docs: 补全全部缺失的 XML 文档注释(中文)

- 为全部 5 个项目(Avalonia-API、Avalonia-Common、Avalonia-EFCore、
  Avalonia-PC、Avalonia-Services)中缺失注释的类、方法、属性、字段、
  接口成员等补全中文 XML 文档注释
- 共修改约 37 个文件,补全约 220+ 处注释
- 修复 ServiceEndpointCollection.cs 中 MapDelete<TService> 语法错误
- 修复 PcAuthService.cs 中 const prefix 位置错乱导致编译失败的问题
- 扫描结果:缺失项 0
- 构建结果:4/4 项目编译通过
This commit is contained in:
2026-05-18 11:35:13 +08:00
parent 446502b0e9
commit fc6f9f6bc3
43 changed files with 884 additions and 233 deletions
@@ -10,6 +10,12 @@ namespace Avalonia_PC.Authentication
/// </summary>
public sealed class DefaultPcThirdPartyAuthorizationClient : IPcThirdPartyAuthorizationClient
{
/// <summary>
/// 验证第三方授权码是否有效。默认实现将 "invalid" 视为授权丢失,其余视为有效。
/// </summary>
/// <param name="authorizationCode">第三方授权码。</param>
/// <param name="cancellationToken">取消令牌。</param>
/// <returns>授权检查结果。</returns>
public Task<ThirdPartyAuthCheckResult> ValidateAuthorizationCodeAsync(
string authorizationCode,
CancellationToken cancellationToken = default)
@@ -23,6 +29,12 @@ namespace Avalonia_PC.Authentication
return Task.FromResult(ThirdPartyAuthCheckResult.Valid);
}
/// <summary>
/// 刷新第三方授权。默认实现总是返回 TemporaryFailure,表示暂时无法刷新。
/// </summary>
/// <param name="authorizationReference">授权引用标识。</param>
/// <param name="cancellationToken">取消令牌。</param>
/// <returns>授权检查结果。</returns>
public Task<ThirdPartyAuthCheckResult> RefreshAuthorizationAsync(
string authorizationReference,
CancellationToken cancellationToken = default)
@@ -8,6 +8,10 @@ using System.Threading.Tasks;
namespace Avalonia_PC.Authentication
{
/// <summary>
/// PC 端鉴权端点服务,实现 <see cref="IPcAuthEndpointService"/>
/// 处理授权码登录、Token 刷新和登出操作。
/// </summary>
public sealed class PcAuthEndpointService(PcGlobalTokenService tokenService) : IPcAuthEndpointService
{
private static readonly JsonSerializerOptions JsonOptions = new()
@@ -15,6 +19,7 @@ namespace Avalonia_PC.Authentication
PropertyNameCaseInsensitive = true,
};
/// <inheritdoc />
public async Task<object?> AuthorizeAsync(ServiceEndpointContext ctx)
{
var request = Deserialize<PcAuthorizeRequest>(ctx.Body);
@@ -28,6 +33,7 @@ namespace Avalonia_PC.Authentication
return ResponseHelper.Ok(token, "授权成功");
}
/// <inheritdoc />
public async Task<object?> RefreshAsync(ServiceEndpointContext ctx)
{
var request = Deserialize<PcRefreshRequest>(ctx.Body);
@@ -42,6 +48,7 @@ namespace Avalonia_PC.Authentication
return ResponseHelper.Ok(refreshed, "刷新成功");
}
/// <inheritdoc />
public Task<object?> LogoutAsync(ServiceEndpointContext ctx)
{
var request = Deserialize<PcLogoutRequest>(ctx.Body);
@@ -50,6 +57,12 @@ namespace Avalonia_PC.Authentication
return Task.FromResult<object?>(ResponseHelper.Succeed("退出成功"));
}
/// <summary>
/// 将 JSON 请求体反序列化为指定类型。
/// </summary>
/// <typeparam name="T">目标类型。</typeparam>
/// <param name="body">JSON 请求体字符串,可为空。</param>
/// <returns>反序列化后的对象;若 body 为空则返回默认值。</returns>
private static T? Deserialize<T>(string? body)
{
return string.IsNullOrWhiteSpace(body)
@@ -57,6 +70,11 @@ namespace Avalonia_PC.Authentication
: JsonSerializer.Deserialize<T>(body, JsonOptions);
}
/// <summary>
/// 从 Authorization 头中提取 Bearer Token。
/// </summary>
/// <param name="authorization">Authorization 头的值。</param>
/// <returns>提取的 Token 字符串;若无法提取则返回 null。</returns>
private static string? ExtractBearerToken(string? authorization)
{
if (string.IsNullOrWhiteSpace(authorization))
@@ -64,7 +82,10 @@ namespace Avalonia_PC.Authentication
return null;
}
const string prefix = "Bearer ";
/// <summary>
/// Bearer Token 的前缀常量。
/// </summary>
const string prefix = "Bearer ";
return authorization.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)
? authorization[prefix.Length..].Trim()
: authorization.Trim();
+11 -1
View File
@@ -6,8 +6,12 @@ using System.Threading.Tasks;
namespace Avalonia_PC.Authentication
{
/// <summary>
/// PC 端鉴权服务,基于全局 Token 验证用户身份,实现 <see cref="IAuthService"/>。
/// </summary>
public sealed class PcAuthService(PcGlobalTokenService tokenService) : IAuthService
{
/// <inheritdoc />
public async Task<ClaimsPrincipal?> AuthenticateAsync(ServiceEndpointContext context)
{
var token = ExtractBearerToken(context.GetHeader("Authorization"));
@@ -29,11 +33,17 @@ namespace Avalonia_PC.Authentication
return new ClaimsPrincipal(identity);
}
/// <inheritdoc />
public Task<bool> AuthorizeAsync(ClaimsPrincipal user, string policy)
{
return Task.FromResult(user.Identity?.IsAuthenticated == true);
}
/// <summary>
/// 从 Authorization 头中提取 Bearer Token。
/// </summary>
/// <param name="authorization">Authorization 头的值。</param>
/// <returns>提取的 Token 字符串;若无法提取则返回 null。</returns>
private static string? ExtractBearerToken(string? authorization)
{
if (string.IsNullOrWhiteSpace(authorization))
@@ -41,7 +51,7 @@ namespace Avalonia_PC.Authentication
return null;
}
const string prefix = "Bearer ";
string prefix = "Bearer ";
return authorization.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)
? authorization[prefix.Length..].Trim()
: authorization.Trim();
@@ -7,16 +7,45 @@ using System.Threading.Tasks;
namespace Authentication
{
/// <summary>
/// PC 端全局 Token 服务,管理全局唯一的访问 Token。
/// 支持授权码登录、Token 刷新、有效性验证和登出,
/// 在第三方授权暂时失败时使用缩短有效期的临时 Token。
/// </summary>
public sealed class PcGlobalTokenService(IPcThirdPartyAuthorizationClient thirdPartyClient)
{
/// <summary>
/// 超级管理员角色集合。
/// </summary>
private static readonly string[] SuperRoles = ["SuperAdmin", "Admin"];
/// <summary>
/// 线程同步锁。
/// </summary>
private readonly object _syncRoot = new();
/// <summary>
/// 当前 Token 状态。
/// </summary>
private PcTokenState? _current;
/// <summary>
/// 正常 Token 有效期(8 小时)。
/// </summary>
private static readonly TimeSpan NormalLifetime = TimeSpan.FromHours(8);
/// <summary>
/// 第三方暂时失败时的 Token 有效期(20 分钟)。
/// </summary>
private static readonly TimeSpan TemporaryFailureLifetime = TimeSpan.FromMinutes(20);
/// <summary>
/// 第三方暂时失败的最长容忍窗口(24 小时),超出后清除 Token。
/// </summary>
private static readonly TimeSpan MaxTemporaryFailureWindow = TimeSpan.FromHours(24);
/// <summary>
/// 使用授权码进行登录授权,验证成功后颁发全局 Token。
/// </summary>
/// <param name="authorizationCode">第三方授权码。</param>
/// <param name="cancellationToken">取消令牌。</param>
/// <returns>Token 响应;若授权码无效则返回 null。</returns>
public async Task<PcTokenResponse?> AuthorizeAsync(string? authorizationCode, CancellationToken cancellationToken = default)
{
if (string.IsNullOrWhiteSpace(authorizationCode))
@@ -33,6 +62,13 @@ namespace Authentication
return IssueToken(authorizationCode, NormalLifetime, resetTemporaryFailureWindow: true);
}
/// <summary>
/// 刷新当前 Token,向第三方验证授权引用是否仍然有效。
/// 根据第三方返回结果决定是续期、降级为临时 Token 还是清除。
/// </summary>
/// <param name="token">当前 Token。</param>
/// <param name="cancellationToken">取消令牌。</param>
/// <returns>新的 Token 响应;若授权丢失则返回 null。</returns>
public async Task<PcTokenResponse?> RefreshAsync(string? token, CancellationToken cancellationToken = default)
{
PcTokenState? current;
@@ -56,6 +92,12 @@ namespace Authentication
};
}
/// <summary>
/// 验证 Token 是否有效,若已过期则尝试自动刷新。
/// </summary>
/// <param name="token">要验证的 Token。</param>
/// <param name="cancellationToken">取消令牌。</param>
/// <returns>Token 是否有效。</returns>
public async Task<bool> ValidateAsync(string? token, CancellationToken cancellationToken = default)
{
PcTokenState? current;
@@ -76,6 +118,10 @@ namespace Authentication
return await RefreshAsync(token, cancellationToken) is not null;
}
/// <summary>
/// 登出并清除当前 Token。
/// </summary>
/// <param name="token">要清除的 Token。</param>
public void Logout(string? token)
{
lock (_syncRoot)
@@ -87,6 +133,13 @@ namespace Authentication
}
}
/// <summary>
/// 颁发新的全局 Token。
/// </summary>
/// <param name="authorizationReference">授权引用标识。</param>
/// <param name="lifetime">Token 有效期。</param>
/// <param name="resetTemporaryFailureWindow">是否重置暂时失败窗口。</param>
/// <returns>包含 Token 和过期时间的响应。</returns>
private PcTokenResponse IssueToken(string authorizationReference, TimeSpan lifetime, bool resetTemporaryFailureWindow)
{
var token = Convert.ToBase64String(RandomNumberGenerator.GetBytes(64));
@@ -105,6 +158,11 @@ namespace Authentication
return new PcTokenResponse(token, state.ExpiresAt, SuperRoles);
}
/// <summary>
/// 在第三方暂时失败时刷新 Token。若超出最大容忍窗口则清除 Token。
/// </summary>
/// <param name="current">当前 Token 状态。</param>
/// <returns>新的临时 Token 响应;若超出容忍窗口则返回 null。</returns>
private PcTokenResponse? RefreshAfterTemporaryFailure(PcTokenState current)
{
var startedAt = current.TemporaryFailureStartedAt ?? DateTime.UtcNow;
@@ -116,6 +174,10 @@ namespace Authentication
return IssueToken(current.AuthorizationReference, TemporaryFailureLifetime, resetTemporaryFailureWindow: false);
}
/// <summary>
/// 清除当前 Token 并返回 null。
/// </summary>
/// <returns>始终返回 null。</returns>
private PcTokenResponse? ClearAndReturnNull()
{
lock (_syncRoot)
@@ -126,6 +188,11 @@ namespace Authentication
return null;
}
/// <summary>
/// 检查给定 Token 是否与当前持有的 Token 匹配。
/// </summary>
/// <param name="token">要检查的 Token。</param>
/// <returns>是否匹配。</returns>
private bool IsCurrentToken(string? token)
{
return !string.IsNullOrWhiteSpace(token) &&
@@ -133,12 +200,24 @@ namespace Authentication
string.Equals(_current.TokenHash, HashToken(token), StringComparison.Ordinal);
}
/// <summary>
/// 对 Token 原文进行 SHA256 哈希,返回十六进制字符串。
/// </summary>
/// <param name="token">Token 原文。</param>
/// <returns>SHA256 哈希后的十六进制字符串。</returns>
private static string HashToken(string token)
{
var bytes = SHA256.HashData(Encoding.UTF8.GetBytes(token));
return Convert.ToHexString(bytes);
}
/// <summary>
/// 保存当前全局 Token 的内部状态。
/// </summary>
/// <param name="TokenHash">Token 的 SHA256 哈希值。</param>
/// <param name="AuthorizationReference">授权引用标识。</param>
/// <param name="ExpiresAt">过期时间。</param>
/// <param name="TemporaryFailureStartedAt">第三方暂时失败的起始时间。</param>
private sealed record PcTokenState(
string TokenHash,
string AuthorizationReference,