Identity 开发指南
本指南帮助开发者在业务代码里消费 Identity 的能力:如何注入服务、做权限检查、处理多租户、管理设备,以及如何扩展模块。所有示例都是 C# 服务调用,不罗列 HTTP 端点(端点见 Swagger)。
从哪里开始
新手入门
- 阅读 架构概览 了解模块整体结构
- 查看 领域能力指南 理解子域划分与关系
- 运行
dotnet run --project src/Services/Identity/FreeKit.Identity.Host启动服务 - 访问 Swagger 查看 API
端到端场景:在业务代码里串联 Identity
下面这些场景不需要关心 HTTP,只注入对应的应用服务即可。
场景一:注册用户并授予权限
public class OnboardingService(
IAccountService accountService,
IPermissionService permissionService)
{
public async Task<Guid> RegisterAndGrantAsync(string userName, string email, string password)
{
// 1) 走注册流程创建用户(注册是用户进入系统的唯一写入口)
var user = await accountService.RegisterAsync(new RegisterReq(userName, email, password));
// 2) 作为"用户级"授予权限
await permissionService.GrantPermissionAsync(new PermissionGrantReq
{
ProviderKey = user.Id.ToString(),
PermissionGrantType = PermissionGrantType.U,
PermissionNames = new[] { "Articles.Create", "Articles.Update" }
});
return user.Id;
}
}
场景二:按权限裁剪列表可见范围
管理员看全部,普通用户只看自己——GetEffectiveUserIdAsync 把"是否有权限"翻译成"要不要加用户过滤":
public async Task<List<MyEntityDto>> GetListAsync(MyEntityQuery query)
{
var (userId, hasPermission) = await GetEffectiveUserIdAsync(
IdentityPermissions.MyFeature.GetList,
query.UserId
);
var queryUserId = (hasPermission && !query.UserId.HasValue)
? (Guid?)null
: userId;
return await _repository.Select
.Where(e => queryUserId == null || e.CreateUserId == queryUserId)
.ToListAsync();
}
场景三:资源所有权检查
操作他人资源前校验归属:
public async Task DeleteAsync(Guid id)
{
var entity = await _repository.FindAsync(id);
if (entity == null)
throw new BusinessException("实体不存在");
var (_, hasPermission) = await GetEffectiveUserIdAsync(
IdentityPermissions.MyFeature.Delete,
entity.CreateUserId
);
if (!hasPermission && entity.CreateUserId != CurrentUser.FindUserId())
throw new BusinessException("无权删除他人资源");
await _repository.DeleteAsync(id);
}
场景四:租户内数据自动隔离
实体实现 ITenant,FreeSql 自动加租户过滤器;必要时可绕过:
// 业务实体
public class MyEntity : FullAuditEntity<Guid, Guid>, ITenant
{
public Guid? TenantId { get; set; }
}
// 自动只查当前租户
var entities = await _repository.Select.ToListAsync();
// 跨租户查询(如后台)
var all = await _repository.Select
.DisableGlobalFilter(GlobalFilterConst.TenantId)
.ToListAsync();
场景五:设备信任管理
注入接口 IUserLoginDeviceManager(实现类 UserLoginDeviceManager)。RemoveDeviceAsync 会级联撤销该设备的 RefreshToken/AccessToken。
private readonly IUserLoginDeviceManager _deviceManager;
// 取某用户设备列表(传入 UserAgent 可标记"当前设备")
List<UserLoginDevice> devices = await _deviceManager.GetDevicesAsync(userId, Request.Headers["User-Agent"]);
// 移除设备(级联吊销其 Token)
await _deviceManager.RemoveDeviceAsync(userId, deviceId);
// 信任设备(默认有效期见 Device:TrustExpireDays,默认 180 天)
await _deviceManager.TrustDeviceAsync(userId, deviceId);
设备验证整体集成在登录流程中(见 设备验证)。
如何扩展模块
如果要在 Identity 内新增一个业务功能,推荐的模式是:权限常量 → 实体 → 应用服务 → 控制器 → 模块注册。
1. 定义权限
public static class MyFeature
{
private const string Default = IdentityPermissions.GroupName + ".MyFeature";
public const string Create = Default + ".Create";
public const string Update = Default + ".Update";
public const string Delete = Default + ".Delete";
}
2. 创建实体
public class MyEntity : FullAuditEntity<Guid, Guid>, ITenant
{
public Guid? TenantId { get; set; }
public string Name { get; set; } = default!;
public string? Description { get; set; }
}
3. 创建应用服务
public class MyEntityService : ApplicationService, IMyEntityService
{
private readonly IBaseRepository<MyEntity, Guid> _repository;
public MyEntityService(IBaseRepository<MyEntity, Guid> repository)
{
_repository = repository;
}
public async Task<List<MyEntityDto>> GetListAsync()
{
var userId = CurrentUser.FindUserId();
return await _repository.Select.OrderByDescending(e => e.CreateTime).ToListAsync();
}
}
4. 创建控制器(启动时自动同步为权限节点)
控制器上的 [Authorize(Policy=...)] 会在模块启动时由 PermissionManager 扫描进权限树,因此"加接口 = 加权限点",无需手工维护:
[ApiExplorerSettings(GroupName = "identity")]
[Area("identity")]
[Route("api/identity/myentity")]
[ApiController]
public class MyEntityController : FreeKitController
{
private readonly IMyEntityService _service;
public MyEntityController(IMyEntityService service) => _service = service;
[HttpGet]
[Authorize(IdentityPermissions.MyFeature.Create)]
public async Task<ApiResponse<List<MyEntityDto>>> GetList()
=> ApiResponse.Ok(await _service.GetListAsync());
}
5. 注册与发现
在模块的 IModuleStartup 中注册服务,并把模块登记到宿主的模块表,框架会自动发现并启动:
public class MyEntityModuleStartup : IModuleStartup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IMyEntityRepository, MyEntityRepository>();
services.AddScoped<IMyEntityService, MyEntityService>();
}
public void Configure(IApplicationBuilder app)
{
var fsql = app.ApplicationServices.GetRequiredService<IFreeSql>();
fsql.CodeFirst.SyncStructure<MyEntity>();
}
}
常见问题
依赖注入未生效
检查是否:1) 实现了 IScopedDependency/ISingletonDependency/ITransientDependency;2) 在模块的 ConfigureServices 中注册;3) 模块已添加到模块表。
权限检查不通过
检查是否:1) 权限已定义在 IdentityPermissions 中;2) 控制器有 [Authorize] 特性;3) 用户/角色/职位有对应的权限授予(PermissionGrant)。
租户数据隔离不生效
检查是否:1) 实体实现了 ITenant;2) 配置了 FreeSql 全局租户过滤器;3) JWT Token 中包含 tenant_id 声明(或请求带 X-Tenant-Id 头)。