IdentityServer4 と PolicyServer.Local を使用するプロジェクトがあります。IdentityServer4 には、必要なデータをデータベースに格納するための実装が既にありますが、PolicyServer にはありません。
それで、私はそれを自分で実装しようとしましたが、成功しましたが、PolicyServers コードの多くを置き換えていると思うという意味では気分が良くありません。
たとえば、すべての PolicyServers エンティティ クラス (ポリシー、アクセス許可、ロール) を置き換え、独自のクラスを追加して、リスト プロパティを解決できるようにしました。これは、Entity Framework が基本的にリストをマップできないためです。
Evaluate-Methods を新しいエンティティ クラスに合わせて調整する必要があったため、独自の PolicyServerRuntimeClient も追加しました。
私の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 の私の Evalute-Methods になります。
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);
しかし、結局、私は予想以上に交換しました。