我有一个项目,我在其中使用 IdentityServer4 和 PolicyServer.Local。IdentityServer4 已经有一个在数据库中存储必要数据的实现,但 PolicyServer 没有。
因此,我尝试自己实现它,并取得了成功,但从某种意义上说,我认为我正在取代大部分 PolicyServers 代码,这感觉并不好。
例如,我已经替换了所有 PolicyServers 实体类(策略、权限、角色)并添加了我自己的,这样我就可以解析列表属性,这一切都是因为实体框架基本上无法映射列表。
我还添加了自己的 PolicyServerRuntimeClient,因为我需要将 Evaluate-Methods 调整为新的实体类。
首先是我的 Startup.cs:
services.AddDbContext<AuthorizeDbContext>(builder =>
builder.UseSqlite(csAuthorizeContext, sqlOptions =>
sqlOptions.MigrationsAssembly(migrationsAssembly)));
services.AddScoped<IAuthorizeService, AuthorizeService>()
.AddTransient<IPolicyServerRuntimeClient, CustomPolicyServerRuntimeClient>()
.AddScoped(provider => provider.GetRequiredService<IOptionsSnapshot<Policy>>().Value);
new PolicyServerBuilder(services).AddAuthorizationPermissionPolicies();
(AuthorizeService 用于从数据库中获取值)
例如,这是我的 Permission-、Roles- 和解决 mn 关系的 PermissionRoles-classes。
public class Permission
{
[Key]
public string Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
[ForeignKey("Policy")]
public string PolicyId { get; set; }
public IList<PermissionRole> PermissionRoles { get; set; }
}
public class PermissionRole
{
[Key]
public string Id { get; set; }
[Required]
public string PermissionId { get; set; }
public Permission Permission { get; set; }
[Required]
public string RoleId { get; set; }
public Role Role { get; set; }
}
public class Role
{
[Key]
public string Id { get; set; }
[Required]
public string Name { get; set; }
public IList<PermissionRole> PermissionRoles { get; set; }
}
这将是我在 CustomPolicyServerRuntimeClient 中的评估方法:
public async Task<PolicyResult> EvaluateAsync(ClaimsPrincipal user)
{
if (user == null)
throw new ArgumentNullException(nameof(user));
var sub = user.FindFirst("sub")?.Value;
if (String.IsNullOrWhiteSpace(sub))
return null;
var roles = _auth.Roles
.ToList()
.Where(x => EvaluateRole(x, user))
.Select(x => x.Name)
.ToArray();
var permissions = _auth.Permissions
.ToList()
.Where(x => EvaluatePermission(x, roles))
.Select(x => x.Name)
.ToArray();
var result = new PolicyResult()
{
Roles = roles.Distinct(),
Permissions = permissions.Distinct()
};
return await Task.FromResult(result);
}
internal bool EvaluateRole(Role role, ClaimsPrincipal user)
{
if (user == null)
throw new ArgumentNullException(nameof(user));
var subClaim = user.FindFirst("sub")?.Value;
var subjectsOfDbRole = _auth.UserDetails
.ToList()
.Where(x => x.RoleId.Equals(role.Id))
.Select(x => x.Subject)
.ToList();
return subjectsOfDbRole.Contains(subClaim);
}
public bool EvaluatePermission(Permission permission, IEnumerable<string> roles)
{
if (roles == null)
throw new ArgumentNullException(nameof(roles));
var permissionRoles = _auth.PermissionRoles
.ToList()
.Where(y => y.PermissionId.Equals(permission.Id))
.ToList();
if (permissionRoles.Any(x => roles.Contains(x.Role.Name)))
return true;
return false;
}
这些是我为使其正常工作所做的主要更改。
在弄清楚如何正确执行此操作之前,我不想在后端做太多工作。
预期的结果是我可能只需要更换
services.Configure<Policy>(configuration);
但最后我确实更换了比预期更多的方式。