Windows認証アプリを作成していますが、ロールはADではなくカスタムデータベース内にあるため、通常はADでロールを確認するUser.IsInRole()関数をオーバーライドするカスタムClaimsPrincipalを作成しました。
ただし、アプリケーションを実行するときは、CustomClaimsPrincipalではなく、元のコードを使用しているようです。 「プライマリドメインと信頼されたドメインの信頼関係に失敗しました」というエラーが表示されます。
ASP.Net MVC 5では、基本的にここで複製しようとしているカスタムRoleProviderを使用しました。
CustomClaimsPrincipal.cs
public class CustomClaimsPrincipal : ClaimsPrincipal
{
private readonly ApplicationDbContext _context;
public CustomClaimsPrincipal(ApplicationDbContext context)
{
_context = context;
}
public override bool IsInRole(string role)
{
var currentUser = ClaimsPrincipal.Current.Identity.Name;
IdentityUser user = _context.Users.FirstOrDefault(u => u.UserName.Equals(currentUser, StringComparison.CurrentCultureIgnoreCase));
var roles = from ur in _context.UserRoles.Where(p => p.UserId == user.Id)
from r in _context.Roles
where ur.RoleId == r.Id
select r.Name;
if (user != null)
return roles.Any(r => r.Equals(role, StringComparison.CurrentCultureIgnoreCase));
else
return false;
}
}
Startup.cs
services.AddIdentity<ApplicationUser, IdentityRole>().AddEntityFrameworkStores<ApplicationDbContext>();
services.AddScoped<ClaimsPrincipal,CustomClaimsPrincipal>();
.Net Coreフレームワークは初めてなので、Startup.csの上記のコードがClaimsPrincipalをオーバーライドする正しい方法であるかどうかはわかりません。
私はその問題に別の方法で取り組むと思います:ClaimsPrincipal
のインスタンスにデータベースと通信させて、それらが特定のロールに属しているかどうかを判断させる代わりに、ClaimsPrincipal
を変更して追加しますClaimsPrincipal
インスタンスでそれらが属するロール。
そのためには、残念ながら十分に文書化されていない機能を使用します。認証パイプラインは、認証が完了すると、作成されたClaimsPrincipal
インスタンスを変換できる拡張ポイントを公開します。これは IClaimsTransformation
インターフェースを介して行うことができます。
コードは次のようになります。
public class Startup
{
public void ConfigureServices(ServiceCollection services)
{
// Here you'd have your registrations
services.AddTransient<IClaimsTransformation, ClaimsTransformer>();
}
}
public class ClaimsTransformer : IClaimsTransformation
{
private readonly ApplicationDbContext _context;
public ClaimsTransformer(ApplicationDbContext context)
{
_context = context;
}
public async Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
{
var existingClaimsIdentity = (ClaimsIdentity)principal.Identity;
var currentUserName = existingClaimsIdentity.Name;
// Initialize a new list of claims for the new identity
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, currentUserName),
// Potentially add more from the existing claims here
};
// Find the user in the DB
// Add as many role claims as they have roles in the DB
IdentityUser user = await _context.Users.FirstOrDefaultAsync(u => u.UserName.Equals(currentUserName, StringComparison.CurrentCultureIgnoreCase));
if (user != null)
{
var rolesNames = from ur in _context.UserRoles.Where(p => p.UserId == user.Id)
from r in _context.Roles
where ur.RoleId == r.Id
select r.Name;
claims.AddRange(rolesNames.Select(x => new Claim(ClaimTypes.Role, x)));
}
// Build and return the new principal
var newClaimsIdentity = new ClaimsIdentity(claims, existingClaimsIdentity.AuthenticationType);
return new ClaimsPrincipal(newClaimsIdentity);
}
}
完全な開示のために、TransformAsync
メソッドは認証プロセスが行われるたびに実行されるため、ほとんどの場合、すべてのリクエストで実行されます。つまり、すべてのリクエストでデータベースにクエリを実行して、ログインしているユーザーのロールを取得します。
ClaimsPrincipal
の実装を変更するよりもこのソリューションを使用する利点は、ClaimsPrincipal
がdumbになり、関連付けられないことです。データベースに。認証パイプラインだけがそれを認識します。これにより、たとえば、特定のロールでClaimsPrincipal
を更新して、特定のアクションを実行するかどうかを確認し、データベースに関連付けられています。