私はこれを約1日半いじり、.NETリフレクターとMSDNのドキュメントをふるいにかけましたが、何もわかりません...
.NET フレームワークでは、次のようにメソッドをマークすることで、現在のプリンシパルがメソッドを実行できるロールに属していることを要求できます。
[PrincipalPermission(SecurityAction.Demand, Role = "CanEdit")]
public void Save() { ... }
「読み取り専用」ロールが既に定義されている既存のセキュリティ モデルを使用しているため、上記とは正反対のことを行う必要があります... ユーザーが「読み取り専用」ロールにある場合は、Save() メソッドをブロックします。問題ありませんよね?SecurityAction を .Deny に切り替えるだけです。
[PrincipalPermission(SecurityAction.Deny, Role = "ReadOnly")]
public void Save() { ... }
さて、これはまったく何もしないことがわかりました。メソッドは引き続き正常に実行されます。PrincipalPermissionAttribute が定義しているようです:
public override IPermission CreatePermission()
ただし、属性が SecurityAction.Deny に設定されている場合、このメソッドは呼び出されないため、IPermission オブジェクトは作成されません。.Deny を機能させる方法を知っている人はいますか? カスタム セキュリティ属性を作成しようとしましたが、それでも機能しません。私はトリッキーになってやろうとしました:
public class MyPermissionAttribute : CodeAccessSecurityAttribute
{
private SecurityAction securityAction;
public MyPermissionAttribute(SecurityAction action)
: base(SecurityAction.Demand)
{
if (action != SecurityAction.Demand && action != SecurityAction.Deny)
throw new ArgumentException("Unsupported SecurityAction. Only Demand and Deny are supported.");
this.securityAction = action;
}
public override IPermission CreatePermission()
{
// do something based on the SecurityAction...
}
}
属性コンストラクターが常に SecurityAction.Demand を渡すことに注意してください。これは、以前は機能していたアクションの 1 つです。ただし、この場合でも、属性が .Deny ではなく .Demand に設定されている場合にのみ、CreatePermission() メソッドが呼び出されます。ランタイムは、CodeAccessSecurityAttribute コンストラクターに渡された SecurityAction ではなく、実際に属性をチェックしているのではないでしょうか?
ここで他に何を試すべきかわかりません...誰かアイデアはありますか? メソッドへのアクセスを要求するだけでなく、ロールに基づいて拒否することはそれほど難しいとは思わないでしょう。デフォルトの PrincipalPermission が .Deny を実行しても問題ないように IDE 内から表示され、MSDN ドキュメントには、それが機能しないことを示唆する 1 ライナーのようなものがあることに本当に悩まされました。.Demand 以外のものが指定された場合、PrincipalPermissionAttribute コンストラクターはすぐに例外をスローすると思うかもしれません。これは、大きなセキュリティ ホールを作成する可能性があるためです。単体テストをしていなかったら、.Deny がまったく何もしないことに気がつかなかったでしょう。
繰り返しますが、これはすべて、アクセスを拒否する必要がある "ReadOnly" ロールを持つ既存のセキュリティ モデルに対処しなければならないことに起因しています。
助けてくれてありがとう!
迅速なフォローアップ:
これを行うことで、実際にカスタム属性を機能させることができます。
public class MyPermissionAttribute : CodeAccessSecurityAttribute
{
public SecurityAction SecurityAction { get; set; }
public MyPermissionAttribute(SecurityAction action)
: base(action)
{
}
public override IPermission CreatePermission()
{
switch(this.SecurityAction) { ... } // check Demand or Deny
}
}
そしてメソッドを飾る:
[MyPermission(SecurityAction.Demand, SecurityAction = SecurityAction.Deny, Role = "ReadOnly")]
public void Save() { ... }
しかし、同じ属性で Demand と Deny の両方を指定しているので、これはひどく醜いです。しかし、それは機能します...
もう 1 つの興味深い点: 私のカスタム クラスは CodeAccessSecurityAttribute を拡張し、さらに SecurityAttribute のみを拡張します。SecurityAttribute を直接拡張するようにカスタム クラスを変更すると、何も機能しなくなります。そのため、ランタイムは間違いなくメタデータ内の CodeAccessSecurityAttribute インスタンスのみを探しており、カスタム コンストラクターがそれをオーバーライドしたとしても、指定された SecurityAction で何かおかしなことをしているようです。