IGeekFan.OpenIddict.FreeSql
OpenIddict 的 FreeSql 存储实现,用于 OAuth2/OIDC 授权服务。
功能概览
| 功能 | 说明 |
|---|---|
| 授权服务 | 构建 OAuth2/OIDC 授权服务器 |
| FreeSql 存储 | OpenIddict 数据持久化到关系型数据库 |
| 授权码/令牌 | 支持授权码、客户端凭证等授权流程 |
| 用户信息 | UserInfo 端点支持 |
安装
dotnet add package IGeekFan.OpenIddict.FreeSql
快速开始
场景:OAuth2 授权服务
1. 配置 FreeSql
using IGeekFan.OpenIddict.FreeSql;
var builder = WebApplication.CreateBuilder(args);
var fsql = new FreeSqlBuilder()
.UseConnectionString(DataType.MySql, builder.Configuration.GetConnectionString("Default"))
.Build();
builder.Services.AddSingleton(fsql);
2. 配置 OpenIddict
builder.Services.AddOpenIddict()
.AddCore(options => options.AddFreeSqlStores())
.AddServer(options =>
{
options.SetAuthorizationEndpointUris("/connect/authorize")
.SetTokenEndpointUris("/connect/token")
.SetUserInfoEndpointUris("/connect/userinfo");
options.AllowAuthorizationCodeFlow()
.AllowRefreshTokenFlow();
options.UseAspNetCore()
.EnableAuthorizationEndpointPassthrough()
.EnableTokenEndpointPassthrough();
})
.AddValidation(options =>
{
options.UseAspNetCore();
});
3. 同步表结构
var app = builder.Build();
// 同步 OpenIddict 表结构
using (var scope = app.Services.CreateScope())
{
var fsql = scope.ServiceProvider.GetRequiredService<IFreeSql>();
fsql.SyncOpenIddictTables();
}
app.Run();
场景:创建 OAuth2 应用
// 创建应用
var application = new OpenIddictApplication
{
ClientId = "my-app",
ClientSecret = "secret",
DisplayName = "My Application",
Permissions = new[]
{
OpenIddictConstants.Permissions.Endpoints.Authorization,
OpenIddictConstants.Permissions.Endpoints.Token,
OpenIddictConstants.Permissions.GrantTypes.AuthorizationCode,
OpenIddictConstants.Permissions.Scopes.Email,
OpenIddictConstants.Permissions.Scopes.Profile,
OpenIddictConstants.Permissions.Scopes.Roles,
OpenIddictConstants.Perscopes.OpenId
}
};
await applicationManager.CreateAsync(application);
高级配置
自定义 Scope
var scope = new OpenIddictScope
{
Name = "api",
DisplayName = "API Access",
Resources = new[] { "api" }
};
await scopeManager.CreateAsync(scope);
自定义声明
builder.Services.AddOpenIddict()
.AddServer(options =>
{
options.Configure(context =>
{
context.Settings["OpenIddict:Claims:sub"] = "UserId";
context.Settings["OpenIddict:Claims:name"] = "UserName";
context.Settings["OpenIddict:Claims:email"] = "Email";
});
});
令牌生命周期
builder.Services.AddOpenIddict()
.AddServer(options =>
{
options.Configure(context =>
{
context.Settings["OpenIddict:Tokens:AccessTokenLifetime"] = "01:00:00";
context.Settings["OpenIddict:Tokens:RefreshTokenLifetime"] = "7.00:00:00";
});
});
数据表
| 表名 | 说明 |
|---|---|
open_iddict_application | 客户端应用 |
open_iddict_authorization | 用户授权记录 |
open_iddict_scope | Scope 定义 |
open_iddict_token | Token 令牌 |
API 示例
授权码流程
// 1. 重定向到授权端点
const authUrl = `${authServer}/connect/authorize?` +
`client_id=${clientId}&` +
`redirect_uri=${redirectUri}&` +
`response_type=code&` +
`scope=openid profile email&` +
`code_challenge=${challenge}&` +
`code_challenge_method=S256`;
// 2. 用户授权后,获取授权码
// 3. 用授权码换取令牌
const tokenResponse = 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: redirectUri,
code_verifier: verifier,
client_id: clientId,
client_secret: clientSecret
})
});
运维建议
| 建议 | 说明 |
|---|---|
| 安全 | 使用 HTTPS |
| 密钥管理 | 定期轮换签名证书 |
| 监控 | 监控令牌颁发和使用 |
| 备份 | 定期备份授权数据 |
故障排查
| 问题 | 解决方案 |
|---|---|
| 表未创建 | 确保调用 SyncOpenIddictTables |
| 令牌无效 | 检查签名证书配置 |
| 授权失败 | 检查应用权限配置 |
| 连接失败 | 检查数据库连接 |
相关文档
- Auth 模块 - 完整认证服务示例
- Identity.FreeSql - 用户认证存储
- Core - 基础包
- 包能力矩阵