System.Web.Http.AuthorizeAttributeから継承して、カスタム承認/認証ルーチンを作成し、ASP.NET MVC 4 を使用して開発された Web アプリケーションのいくつかの異常な要件を満たすようにしています。これにより、Web からの Ajax 呼び出しに使用される Web API にセキュリティが追加されます。クライアント。要件は次のとおりです。
- ユーザーは、トランザクションを実行するたびにログオンして、誰かがログオンして立ち去った後、他の誰かがワークステーションに近づいていないことを確認する必要があります。
- プログラム時にロールを Web サービス メソッドに割り当てることはできません。管理者がこれを構成できるように、実行時に割り当てる必要があります。この情報は、システム データベースに保存されます。
Web クライアントはシングル ページ アプリケーション (SPA)であるため、通常のフォーム認証はうまく機能しませんが、要件を満たすために ASP.NET セキュリティ フレームワークをできる限り再利用しようとしています。カスタマイズされたAuthorizeAttributeは、Web サービス メソッドに関連付けられているロールを決定する要件 2 に最適です。アプリケーション名、リソース名、および操作の 3 つのパラメーターを受け入れて、どのロールがメソッドに関連付けられているかを判断します。
public class DoThisController : ApiController
{
[Authorize(Application = "MyApp", Resource = "DoThis", Operation = "read")]
public string GetData()
{
return "We did this.";
}
}
OnAuthorizationメソッドをオーバーライドして、ロールを取得し、ユーザーを認証します。ユーザーはトランザクションごとに認証を受ける必要があるため、認証と承認を同じ手順で実行することで、やり取りを減らすことができます。HTTP ヘッダーで暗号化された資格情報を渡す基本認証を使用して、Web クライアントからユーザーの資格情報を取得します。したがって、私のOnAuthorizationメソッドは次のようになります。
public override void OnAuthorization(HttpActionContext actionContext)
{
string username;
string password;
if (GetUserNameAndPassword(actionContext, out username, out password))
{
if (Membership.ValidateUser(username, password))
{
FormsAuthentication.SetAuthCookie(username, false);
base.Roles = GetResourceOperationRoles();
}
else
{
FormsAuthentication.SignOut();
base.Roles = "";
}
}
else
{
FormsAuthentication.SignOut();
base.Roles = "";
}
base.OnAuthorization(actionContext);
}
GetUserNameAndPasswordは、HTTP ヘッダーから資格情報を取得します。次に、Membership.ValidateUserを使用して資格情報を検証します。カスタム データベースにアクセスするために、カスタム メンバーシップ プロバイダーとロール プロバイダーをプラグインしています。ユーザーが認証されたら、リソースと操作のロールを取得します。そこから、ベースのOnAuthorizationを使用して認証プロセスを完了します。ここが壊れるところです。
ユーザーが認証されている場合は、標準のフォーム認証方法を使用してユーザーをログインさせ (FormsAuthentication.SetAuthCookie)、失敗した場合はログアウトさせます (FormsAuthentication.SignOut)。しかし、問題は、ベースの OnAuthorizationクラスが、 IsAuthenticatedが正しい値に設定されるように更新されたプリンシパルにアクセスできないことです。いつも一歩後ろです。そして、Web クライアントへの往復があるまで更新されないキャッシュされた値を使用していると思います。
つまり、Cookie を使用せずにIsAuthenticatedを現在のプリンシパルの正しい値に設定する別の方法はありますか? 毎回認証する必要があるこの特定のシナリオでは、Cookie は実際には適用されないように思えます。IsAuthenticatedが正しい値に設定されていないことがわかっている理由は、 HandleUnauthorizedRequestメソッドもこれにオーバーライドしているためです。
protected override void HandleUnauthorizedRequest(HttpActionContext filterContext)
{
if (((System.Web.HttpContext.Current.User).Identity).IsAuthenticated)
{
filterContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.Forbidden);
}
else
{
base.HandleUnauthorizedRequest(filterContext);
}
}
これにより、失敗の原因が認証ではなく承認であった場合に、Forbidden のステータス コードを Web クライアントに返すことができ、それに応じて応答できます。
では、このシナリオで現在のプリンシパルにIsAuthenticatedを設定する適切な方法は何ですか?