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" />
<PackageReference Include="BugFree.Login" />
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
#tool nuget:?package=BugFree.Login&version=1.2.2026.616-beta0932&prerelease
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.SecurityPasswordHashServiceBCrypt 哈希(WorkFactor) - 验证码:SHA256 摘要存储,不存明文;
BugFree.CoreSecureRandomStringGenerator生成 - 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 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
-
net10.0
- BugFree.Security (>= 1.2.2026.614-beta1531)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.9)
- Microsoft.Extensions.Options (>= 10.0.9)
- Microsoft.IdentityModel.JsonWebTokens (>= 8.19.1)
-
net8.0
- BugFree.Security (>= 1.2.2026.614-beta1531)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.9)
- Microsoft.Extensions.Options (>= 10.0.9)
- Microsoft.IdentityModel.JsonWebTokens (>= 8.19.1)
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 |