VOOZH about

URL: https://www.nuget.org/packages/BugFree.Login/

⇱ NuGet Gallery | BugFree.Login 1.2.2026.616-beta0932




👁 Image
BugFree.Login 1.2.2026.616-beta0932

This is a prerelease version of BugFree.Login.
dotnet add package BugFree.Login --version 1.2.2026.616-beta0932
 
 
NuGet\Install-Package BugFree.Login -Version 1.2.2026.616-beta0932
 
 
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="BugFree.Login" Version="1.2.2026.616-beta0932" />
 
 
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="BugFree.Login" Version="1.2.2026.616-beta0932" />
 
Directory.Packages.props
<PackageReference Include="BugFree.Login" />
 
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add BugFree.Login --version 1.2.2026.616-beta0932
 
 
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
#r "nuget: BugFree.Login, 1.2.2026.616-beta0932"
 
 
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package BugFree.Login@1.2.2026.616-beta0932
 
 
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=BugFree.Login&version=1.2.2026.616-beta0932&prerelease
 
Install as a Cake Addin
#tool nuget:?package=BugFree.Login&version=1.2.2026.616-beta0932&prerelease
 
Install as a Cake Tool
The NuGet Team does not provide support for this client. Please contact its maintainers for support.

BugFree.Login

统一登录认证中心核心组件,为 .NET 应用提供开箱即用的本地认证能力。

✨ 功能特性

认证方式 说明
账号密码登录 用户名/手机号/邮箱 + 密码,BCrypt 哈希验证
短信验证码登录 手机号 + 6 位短信验证码,SHA256 摘要存储
邮箱验证码登录 邮箱 + 6 位邮箱验证码
邮件魔法链接 邮箱 + 一次性魔法链接,无密码登录
  • JWT AccessToken 签发(HS256 签名)+ RefreshToken 轮换与撤销
  • Challenge 机制:验证码/魔法链接的 SHA256 摘要存储 + 一次性消费防重放
  • 自动发送(可选):注册 IChallengeSender 后,创建挑战码时自动发送
  • 统一错误码(AuthErrorCodes),不泄露敏感信息
  • 零过度设计:核心库只做抽象 + 编排 + 安全实现,不含 UI、数据库、短信服务商

📦 安装

dotnet add package BugFree.Login

🚀 快速开始

1. 注册服务

using BugFree.Login.Extensions;

builder.Services.AddBugFreeLogin(jwt =>
{
 jwt.Secret = "your-256-bit-secret-key-at-least-32-chars!";
 jwt.Issuer = "MyApp";
 jwt.Audience = "MyApp";
});

2. 必须实现的契约

调用方需要实现以下接口,否则核心库无法运行:

2.1 IUserStore(必须)

用户查找、密码哈希读取、状态检查。

public class MyUserStore : IUserStore
{
 public async Task<UserInfo?> FindByAccountAsync(string account, CancellationToken ct)
 {
 // 按账号/手机号/邮箱查找用户
 }

 public async Task<string?> GetPasswordHashAsync(long userId, CancellationToken ct)
 {
 // 返回 BCrypt 哈希,无密码返回 null
 }

 public async Task<UserStatus> GetStatusAsync(long userId, CancellationToken ct)
 {
 // Active / Disabled / Locked
 }
}
2.2 ITokenStore(必须)

RefreshToken 生命周期管理(原文不存,只存 SHA256 摘要)。

public class MyTokenStore : ITokenStore
{
 public async Task SaveAsync(TokenEntry entry, CancellationToken ct) { }
 public async Task<TokenEntry?> GetAsync(string refreshTokenHash, CancellationToken ct) => null;
 public async Task<bool> RevokeAsync(string refreshTokenHash, CancellationToken ct) => false;
 public async Task<int> RevokeAllForUserAsync(long userId, CancellationToken ct) => 0;
}
2.3 IChallengeStore(必须)

验证码/魔法链接的临时存储(一次性消费,原子操作)。

public class MyChallengeStore : IChallengeStore
{
 public async Task SaveAsync(ChallengeEntry entry, CancellationToken ct) { }
 public async Task<ChallengeEntry?> GetAsync(string challengeId, CancellationToken ct) => null;
 public async Task<bool> ConsumeAsync(string challengeId, CancellationToken ct) => false;
}
2.4 IChallengeSender(可选)

注册后,ChallengeService.CreateChallengeAsync 会自动调用发送验证码/链接。未注册则返回 rawCode 由调用方自行处理。

public class MyChallengeSender : IChallengeSender
{
 readonly ISmsService _sms;
 readonly IEmailService _email;
 readonly string _baseUrl;

 public async Task SendAsync(AuthProviderType type, string target, string challengeId, string code, CancellationToken ct)
 {
 switch (type)
 {
 case AuthProviderType.SmsCode:
 await _sms.SendAsync(target, $"您的登录验证码是:{code}", ct);
 break;
 case AuthProviderType.EmailCode:
 await _email.SendAsync(target, "登录验证码", $"您的验证码是:{code}", ct);
 break;
 case AuthProviderType.EmailLink:
 var link = $"{_baseUrl}/auth/magic-link?c={challengeId}&t={code}";
 await _email.SendAsync(target, "登录链接", $"点击链接登录:{link}", ct);
 break;
 }
 }
}
注册所有实现
// 必须实现
builder.Services.AddSingleton<IUserStore, MyUserStore>();
builder.Services.AddSingleton<ITokenStore, MyTokenStore>();
builder.Services.AddSingleton<IChallengeStore, MyChallengeStore>();

// 可选(自动发送验证码)
builder.Services.AddScoped<IChallengeSender, MyChallengeSender>();

// 核心服务(一行注册完成)
builder.Services.AddBugFreeLogin(jwt =>
{
 jwt.Secret = "your-256-bit-secret-key-at-least-32-chars!";
 jwt.Issuer = "MyApp";
 jwt.Audience = "MyApp";
});

3. 发起密码登录

var result = await authManager.AuthenticateAsync(new LoginRequest
{
 Account = "user@example.com",
 Credential = "password123",
 ProviderType = AuthProviderType.Password,
}, new AuthContext { IP = "127.0.0.1", DeviceId = "web-1" });

if (result.Success)
{
 var accessToken = result.TokenPair!.AccessToken;
 var refreshToken = result.TokenPair.RefreshToken;
}

4. 发送验证码并登录

// 注册了 IChallengeSender 后,自动发送
var (challengeId, _) = await challengeService.CreateChallengeAsync(
 AuthProviderType.SmsCode, "13800138000");
// 短信已自动发出 ✓

// 用户提交验证码登录
var result = await authManager.AuthenticateAsync(new LoginRequest
{
 Account = "13800138000",
 Credential = userInputCode,
 ProviderType = AuthProviderType.SmsCode,
 ChallengeId = challengeId,
}, context);

📁 项目结构

BugFree.Login/
├── Abstractions/ 契约层(按功能域划分)
│ ├── Auth/ 认证模型 + IAuthProvider
│ ├── Token/ Token 模型 + IJwtService + ITokenStore
│ ├── Challenge/ ChallengeEntry + IChallengeService + IChallengeStore + IChallengeSender
│ └── User/ UserInfo + UserStatus + IUserStore
├── Errors/ AuthErrorCodes 稳定错误码
├── Extensions/ AddBugFreeLogin() DI 注册
├── Providers/ AuthManager + PasswordAuthProvider + ChallengeAuthProvider
└── Services/ ChallengeService + DefaultJwtService(实现)
BugFree.Login.Tests/ 41 个单元测试(xUnit + Moq)

🔒 安全要点

  • 密码:BugFree.Security PasswordHashService BCrypt 哈希(WorkFactor)
  • 验证码:SHA256 摘要存储,不存明文;BugFree.Core SecureRandomStringGenerator 生成
  • Token:RefreshToken 原文不存库,只存 SHA256 摘要
  • Challenge:一次性消费 + 5 分钟自动过期 + 原子性消费防并发重放
  • RefreshToken:轮换时旧 Token 立即撤销
  • 错误信息:不泄露密码/验证码/Token 等敏感数据
  • 生产环境:必须配置强随机 JWT 密钥

🧪 测试

dotnet test

覆盖场景:

  • 密码登录:成功 / 用户不存在 / 禁用 / 锁定 / 密码错误 / 无密码哈希
  • Challenge 登录:成功 / ChallengeId 缺失 / 验证码错误 / 用户不存在 / 禁用 / 锁定 / 魔法链接消息
  • JWT:签发 / sub claim 验证 / RefreshToken 轮换 / 撤销 / 过期 / 未找到
  • BCrypt(PasswordHashService):哈希 / 随机盐值 / 验证 / 错误密码 / 空密码 / 空哈希
  • AuthManager:分派 / 不支持 Provider
  • LoginResult:Ok / Fail 工厂方法

📄 License

MIT

  • 密码:BCrypt 哈希(WorkFactor=12),自动随机盐值
  • 验证码:SHA256 摘要存储,不存明文;密码学安全随机数生成
  • Token:RefreshToken 原文不存库,只存 SHA256 摘要
  • Challenge:一次性消费,过期自动失效(默认 5 分钟)
  • RefreshToken:轮换时旧 Token 立即撤销
  • 错误信息:不泄露密码/验证码/Token 等敏感数据
  • 生产环境:必须配置强随机 JWT 密钥

🧪 测试

dotnet test

覆盖场景:

  • ✅ 密码登录:成功 / 用户不存在 / 禁用 / 锁定 / 密码错误 / 无密码哈希
  • ✅ 短信验证码登录:成功 / 验证码错误 / 过期 / 已消费 / Challenge 不存在
  • ✅ 邮箱验证码登录 / 魔法链接登录
  • ✅ JWT 签发 / RefreshToken 轮换 / 撤销 / 过期
  • ✅ BCrypt 哈希 / 验证
  • ✅ AuthManager 分派 / 不支持 Provider

📄 License

MIT

Product Versions Compatible and additional computed target framework versions.
.NET net8.0 net8.0 is compatible.  net8.0-android net8.0-android was computed.  net8.0-browser net8.0-browser was computed.  net8.0-ios net8.0-ios was computed.  net8.0-maccatalyst net8.0-maccatalyst was computed.  net8.0-macos net8.0-macos was computed.  net8.0-tvos net8.0-tvos was computed.  net8.0-windows net8.0-windows was computed.  net9.0 net9.0 was computed.  net9.0-android net9.0-android was computed.  net9.0-browser net9.0-browser was computed.  net9.0-ios net9.0-ios was computed.  net9.0-maccatalyst net9.0-maccatalyst was computed.  net9.0-macos net9.0-macos was computed.  net9.0-tvos net9.0-tvos was computed.  net9.0-windows net9.0-windows was computed.  net10.0 net10.0 is compatible.  net10.0-android net10.0-android was computed.  net10.0-browser net10.0-browser was computed.  net10.0-ios net10.0-ios was computed.  net10.0-maccatalyst net10.0-maccatalyst was computed.  net10.0-macos net10.0-macos was computed.  net10.0-tvos net10.0-tvos was computed.  net10.0-windows net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.2.2026.616-beta0932 42 6/16/2026
1.2.2026.615-beta1139 43 6/15/2026
1.2.2026.614-beta1731 43 6/14/2026