Auth 认证中心模块
Auth 模块基于 OpenIddict 7.5 实现 OAuth2/OpenID Connect 认证服务,支持授权码流、PKCE、刷新令牌。
功能概览
Auth 模块基于 OpenIddict 实现 OAuth2/OpenID Connect 认证服务,提供:
| 功能域 | 能力 |
|---|---|
| OAuth2 端点 | /connect/authorize、/connect/token、/connect/userinfo、/connect/logout |
| 认证流程 | 授权码流、PKCE、刷新令牌 |
| 应用管理 | OAuth2 客户端应用 CRUD、Scope 管理、Token 管理 |
| 声明映射 | 动态声明映射(数据库配置)、默认 Scope(openid/profile/email/roles) |
| 安全 | 密码策略(5 次锁定)、证书签名、Token 撤销与清理 |
| 启动引导 | 自动创建 Scope 和应用、非破坏性合并 |
快速开始
1. 配置数据库
{
"ConnectionStrings": {
"DefaultDB": "0",
"DataType": { "MySql": 0, "Sqlite": 4 },
"MySql": "server=localhost;port=3306;database=freekit;uid=root;pwd=123456;",
"Sqlite": "Data Source=freekit.auth.db"
}
}
2. 配置证书
{
"Security:OpenIddict:Certificates": {
"SigningCertificatePath": "signing.pfx",
"SigningCertificatePassword": "your-password",
"EncryptionCertificatePath": "encryption.pfx",
"EncryptionCertificatePassword": "your-password"
}
}
3. 启动服务
dotnet run --project src/Services/Auth/FreeKit.Auth.Host
架构概览
OAuth2 端点
/connect/authorize
OAuth2 授权端点,支持授权码流。
| 参数 | 说明 |
|---|---|
client_id | 客户端 ID |
redirect_uri | 回调地址 |
response_type | 响应类型(code) |
scope | 请求的 Scope |
code_challenge | PKCE 挑战 |
code_challenge_method | 挑战方法(S256) |
/connect/token
令牌端点,支持授权码和刷新令牌。
| 参数 | 说明 |
|---|---|
grant_type | 授权类型 |
code | 授权码 |
redirect_uri | 回调地址 |
code_verifier | PKCE 验证器 |
refresh_token | 刷新令牌 |
/connect/userinfo
返回用户信息,基于授权的 Scope。
| Scope | 返回的 Claims |
|---|---|
openid | sub |
profile | name |
email | email |
roles | role |
/connect/logout
登出,撤销所有有效令牌。
核心功能
用户认证
支持用户名或邮箱登录,大小写不敏感。
认证流程
- 查找用户(用户名/邮箱)
- 检查账户锁定状态
- 验证密码哈希
- 记录失败尝试
- 5 次失败后锁定 30 分钟
密码策略
| 配置 | 说明 |
|---|---|
| 最大失败次数 | 5 次 |
| 锁定时间 | 30 分钟 |
| 密码哈希 | ASP.NET Identity PasswordHasher |
| 自动重哈希 | 支持 |
动态声明映射
支持从数据库配置的动态声明映射。
映射实体
| 字段 | 类型 | 说明 |
|---|---|---|
ClaimType | string | 声明类型 |
UserPropertyName | string | 用户属性名 |
SourceType | ClaimSourceType | 来源类型 |
IsEnabled | bool | 是否启用 |
Scopes | string? | 关联的 Scope |
默认映射
| 声明类型 | 来源 | 需要的 Scope |
|---|---|---|
sub | AuthUser.Id | openid |
name | AuthUser.UserName | profile |
email | AuthUser.Email | email |
role | 用户角色 | roles |
OAuth2 应用管理
管理 OAuth2 客户端应用。
应用属性
| 属性 | 说明 |
|---|---|
ClientId | 客户端 ID |
ClientSecret | 客户端密钥 |
DisplayName | 显示名称 |
ApplicationType | 应用类型 |
ConsentType | 同意类型 |
RedirectUris | 回调地址 |
PostLogoutRedirectUris | 登出回调 |
Scopes | 允许的 Scope |
Permissions | 权限 |
Scope 管理
管理 OAuth2 Scope。
内置 Scope
| Scope | 显示名称 | 资源 |
|---|---|---|
openid | OpenID | identity |
profile | 用户资料 | identity |
email | 邮箱信息 | identity |
roles | 角色信息 | identity |
console | Console API | console |
cmskit | CmsKit API | cmskit |
im | IM API | im |
Token 管理
管理访问令牌和刷新令牌。
| 功能 | 说明 |
|---|---|
| 列出 Token | 分页查询 |
| 撤销 Token | 单个/批量撤销 |
| 清理 Token | 清理已兑换/已撤销的旧 Token |
启动引导
OpenIddictBootstrapper 在启动时自动配置:
| 功能 | 说明 |
|---|---|
| 确保 Scope | 自动创建内置 Scope |
| 确保应用 | 自动创建配置的应用 |
| 非破坏性合并 | 不覆盖已有记录 |
API 控制器
ConnectController
| 方法 | 路由 | 认证 | 说明 |
|---|---|---|---|
| GET | /connect/authorize | Anonymous | 授权端点 |
| POST | /connect/token | Anonymous | 令牌端点 |
| GET | /connect/userinfo | OpenIddict | 用户信息 |
| POST | /connect/logout | Cookie | 登出 |
OpenIddictAdminController
| 方法 | 路由 | 认证 | 说明 |
|---|---|---|---|
| GET | /api/identity/openiddict/applications | Admin | 列出应用 |
| GET | /api/identity/openiddict/applications/{id} | Admin | 获取应用 |
| POST | /api/identity/openiddict/applications | Admin | 创建应用 |
| PUT | /api/identity/openiddict/applications/{id} | Admin | 更新应用 |
| DELETE | /api/identity/openiddict/applications/{id} | Admin | 删除应用 |
| GET | /api/identity/openiddict/scopes | Admin | 列出 Scope |
| POST | /api/identity/openiddict/scopes | Admin | 创建 Scope |
| DELETE | /api/identity/openiddict/scopes/{id} | Admin | 删除 Scope |
| GET | /api/identity/openiddict/tokens | Admin | 列出 Token |
| POST | /api/identity/openiddict/tokens/{id}/revoke | Admin | 撤销 Token |
| POST | /api/identity/openiddict/tokens/revoke-by-subject | Admin | 撤销用户 Token |
| POST | /api/identity/openiddict/tokens/revoke-by-application/{appId} | Admin | 撤销应用 Token |
| POST | /api/identity/openiddict/tokens/prune | Admin | 清理旧 Token |
| GET | /api/identity/openiddict/authorizations | Admin | 列出授权 |
配置选项
数据库配置
{
"ConnectionStrings": {
"DefaultDB": "0",
"DataType": { "MySql": 0, "Sqlite": 4 },
"MySql": "server=localhost;port=3306;database=freekit_auth;uid=root;pwd=123456;",
"Sqlite": "Data Source=freekit.auth.db"
}
}
证书配置
{
"Security:OpenIddict:Certificates": {
"SigningCertificatePath": "signing.pfx",
"SigningCertificatePassword": "your-password",
"EncryptionCertificatePath": "encryption.pfx",
"EncryptionCertificatePassword": "your-password"
}
}
应用配置
{
"Security:OpenIddict:Bootstrap": {
"Enabled": true,
"Applications": [
{
"ClientId": "console",
"ClientSecret": "console-secret",
"DisplayName": "Console Application",
"RedirectUris": ["{CmsKitClient}/callback"],
"PostLogoutRedirectUris": ["{CmsKitClient}"],
"Scopes": ["openid", "profile", "email", "roles", "console", "cmskit"]
}
]
}
}
环境变量
| 变量 | 说明 |
|---|---|
ASPNETCORE_ENVIRONMENT | 运行环境 |
IdentityApi | 认证服务地址 |
CmsKitClient | 前端客户端地址 |
数据库表
| 表名 | 说明 |
|---|---|
identity_user | 用户表 |
identity_role | 角色表 |
identity_user_role | 用户角色关联 |
identity_connect_claim_mapping | 声明映射表 |
open_iddict_application | OAuth2 应用表 |
open_iddict_authorization | 授权记录表 |
open_iddict_scope | Scope 表 |
open_iddict_token | Token 表 |
与前端集成
1. 配置回调地址
// 前端回调地址
const callbackUrl = `${authServer}/connect/callback`;
2. 获取授权码
// 重定向到授权端点
const authUrl = `${authServer}/connect/authorize?` +
`client_id=${clientId}&` +
`redirect_uri=${callbackUrl}&` +
`response_type=code&` +
`scope=openid profile email&` +
`code_challenge=${challenge}&` +
`code_challenge_method=S256`;
3. 交换令牌
const response = await fetch(`${authServer}/connect/token`, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'authorization_code',
code: authorizationCode,
redirect_uri: callbackUrl,
code_verifier: verifier,
client_id: clientId,
client_secret: clientSecret
})
});
4. 刷新令牌
const response = await fetch(`${authServer}/connect/token`, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'refresh_token',
refresh_token: refreshToken,
client_id: clientId,
client_secret: clientSecret
})
});