PrincipalPermissionAttribute のように、Thread.CurrentPrincipal の代わりに AuthenticationService を使用するカスタム PrincipalPermissionAttribute を作成しました。
思い通りに動作しますが、ユーザーがログアウトして再度ログインした場合、またはユーザーの役割が変更された場合、属性コードが 2 回呼び出されることはありません。許可を再確認する必要がある属性に通知していないのではないでしょうか? CreatePermission メソッドに設定されたブレークポイントは、一度しかヒットしません。
属性コードは一度だけ評価されますか? 属性は現在、ビューのコードビハインドでのボタン クリックのイベント ハンドラーを装飾しています。
メソッドを変更して PrincipalPermissionAttribute を使用するように戻すと、期待どおりに機能し、適切なロールを持たないユーザーとしてログアウトして再度ログインすると、期待どおりの SecurityException がスローされます。おそらくプロパティのオーバーライドを逃しましたか?
[Serializable]
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
public sealed class RolePermissionAttribute : CodeAccessSecurityAttribute
{
private readonly PrincipalPermission _revoke = new PrincipalPermission(PermissionState.None);
private readonly PrincipalPermission _allow = new PrincipalPermission(PermissionState.Unrestricted);
private IList<string> _roles;
private readonly IAuthenticationService _authorisationService;
public RolePermissionAttribute(SecurityAction action)
: this(action, ServiceLocator.Current.GetInstance<IAuthenticationService>())
{
}
public RolePermissionAttribute(SecurityAction action, IAuthenticationService authorisationService)
: base(action)
{
_authorisationService = authorisationService;
}
public string Roles { get; set; }
public bool Authenticated { get; set; }
public override IPermission CreatePermission()
{
_roles = (this.Roles ?? string.Empty).Split(',', ';')
.Select(s => s.Trim())
.Where(s => s.Length > 0)
.Distinct()
.ToList();
bool result = false;
if (_authorisationService != null)
{
var principal = _authorisationService.ClientSecurityPrincipal;
if (principal == null)
{
throw new SecurityException("Access Denied. You are not logged in");
}
// If Authenticated is enforced then revoke if user is not authenticated
if (Authenticated && !_authorisationService.IsAuthenticated)
{
throw new SecurityException("Access Denied. You are not authenticated");
}
// Allow if the principal is in any of the roles
result = _roles.Any(principal.IsInRole);
if (!result)
{
throw new SecurityException("Access Denied. You are not in an allowed Role");
}
}
return result ? _allow : _revoke;
}
}
}
属性を使用したメソッドは次のとおりです
[RolePermission(SecurityAction.Demand, Authenticated = true, Roles = "Admin")]
private void barButtonItemConfig_ItemClick(object sender, ItemClickEventArgs e)
{
// Do stuff
}