カスタム属性クラスにおける、インスタンスの生成時期(リッチクライアントとロールベースセキュリティ (3))

クラス又はメソッドに対して、実行時に認証を強要するカスタム属性クラスをSystem.Attributeクラスから派生して実装することを考えている。

//クラスに対して宣言
[AuthenticateRequire("Kazzz", "User")]
public class Hoge : IHoge
{
  〜
}

//メソッドに対して宣言
[AuthenticateRequire("Kazzz", "User")]
public void Run()
{
  〜
}

クラスに対して宣言した場合はクラスのロード時(通常スタティックコンストラクタが動いた時か、通常のコンストラクタが動いた時でよいだろう)、メソッドに対して宣言した場合はメソッドの実行前に認証を強制する訳だ。

この部分、以前の日記でも書いたとおり、最初はAOPで実装しようと思ったのだが、その後、拙作のフレームワークに限定して言えばセキュリティチェックが必要になってくるタイミングはほぼ特定のクラス(及びその派生クラス)の特定のメソッドに限定できるので(まあ、だからこそフレームワークなのだが)、現状は敢えてAOPにする必要は無いと判断するに至った。しかし、セキュリティチェックがどこに入らるか判らない状況になる可能性も捨てきれないので、AOPは使わないが、予めセキュリティチェックを宣言できる、カスタム属性を利用することにしたわけだ。
万が一、セキュリティチェックの位置が一定じゃなくなった場合は、AOPと組み合わせて、全てのメソッドに対して、セキュリティチェックが必要なことが宣言されているかを検査できることだろう。

カスタム属性"AuthenticateRequireAttribute"クラスのコンストラクタ引数は、それぞれ、IPrincipalとIIdentityインタフェースの実装のために使用する"主体の名前"と"ロールメンバシップ"として使う。これは元々.NETの宣言的セキュリティチェックで提供されているPrincipalPermissionAttributeと同じである。

[AttributeUsage(
      AttributeTargets.Method 
    | AttributeTargets.Constructor 
    | AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
[Serializable]
public class AuthenticateRequireAttribute : Attribute 
{
    private bool authenticated;
    private string name;
    private string role;

    public AuthenticateRequireAttribute (string name, string role)
        :base()
    {
        this.name = name;
        this.role = role;
        this.authenticated = false;
    }
}
〜

さて、AOPを使わないのであれば、このカスタム属性がクラス、又はメソッド部で宣言されているかを自ら調べなくてはならない。以下のようなコードで調べることで可能だろう。

//Hogeクラスに対して宣言されているカスタム属性を取得
Attribute attrs_class = Attribute.GetCustomAttributes(typeof(Hoge), typeof(AuthenticateRequire), true);

//Run()メソッドに対して宣言されているカスタム属性を取得
Attribute attrs_method = Attribute.GetCustomAttributes(typeof(Hoge).GetMethod("Run", new Type[0]), typeof(AuthenticateRequire), true);

Attribute配列の要素数はカスタム属性が宣言されている数であり、それぞれの要素が必要なセキュリティチェックの内容を示している。例えば、サンプルで出てきたような

[AuthenticateRequire("Kazzz", "User")]

という宣言であれば、ユーザ名"Kazzz"、ロールメンバシップ"User"を含んでいるPrincipalオブジェクトがスレッドにバインドされていることを強制する訳だ。(ダイアログ認証を使う、BASIC認証を使う、などの認証の方法に関しては、別途、そのストラテジを用意することにするが、今回は省いている)

カスタム属性はそのままでは単なるアノテーションの一種であり、オブジェクトではない。では、実際にカスタム属性のインスタンスが生成されるのは、どのタイミングなのだろう。それは意外というか予想通りというか、トレースすれば一目瞭然だが、正にAttribute.GetCustomAttributesメソッドが実行された時なのである。