web-dev-qa-db-ja.com

ASP.NET MVCでログインシステムを作成できますが、メンバーシッププロバイダーを使用できませんか?

Usersテーブルを含む既存のデータベースがあり、データベースを取得して、ASP.NET MVCで構築された新しいシステムに使用することを計画しています。ただし、既存のテーブル構造を引き続き使用できるように、組み込みのアカウントコントローラーまたは通常のメンバーシッププロバイダーを使用しないログインシステムを作成できるかどうかについては、はっきりしません。

だから私の質問は、これは可能でしょうか?それとも、そうするのが特に難しいですか?

最も広く受け入れられている最も簡単な方法は何ですか?

58
LiamGu

これとまったく同じ要件がありました。自分のユーザーとロールスキーマがあり、asp.netメンバーシップスキーマに移行したくありませんでしたが、承認とロールを確認するためにASP.NET MVCアクションフィルターを使用しました。何をする必要があるのか​​を正確に見つけるために、かなりの量の掘り下げを行わなければなりませんでしたが、結局それは比較的簡単でした。私はあなたをトラブルから救い、私が何をしたかをお話しします。

1)System.Web.Security.MembershipProviderから派生したクラスを作成しました。 MembershipProviderには、パスワードを忘れた、パスワードを変更した、新しいユーザーを作成したなど、あらゆる種類の認証関連機能のための多数の抽象メソッドがあります。私が欲しかったのは、自分のスキーマに対して認証する機能だけでした。したがって、私のクラスには主に空のオーバーライドが含まれていました。 ValidateUserをオーバーライドしました:

public override bool ValidateUser(string username, string password)
{
    if (string.IsNullOrWhiteSpace(username) ||
        string.IsNullOrWhiteSpace(password))
      return false;

    string hash = EncryptPassword(password);
    User user = _repository.GetByUserName(username);
    if (user == null) return false;

    return user.Password == hash;
}

2)System.Web.Security.RoleProviderから派生したクラスを作成しました。繰り返しますが、私は、ロールの作成や変更のように必要のないすべての綿密な実装を空にしました。 2つのメソッドをオーバーライドしました。

public override string[] GetRolesForUser(string username)
{
    User user = _repository.GetByUserName(username);
    string[] roles = new string[user.Role.Rights.Count + 1];
    roles[0] = user.Role.Description;
    int idx = 0;
    foreach (Right right in user.Role.Rights)
        roles[++idx] = right.Description;
    return roles;
}

public override bool IsUserInRole(string username, string roleName)
{
    User user = _repository.GetByUserName(username);
    if(user!=null)
        return user.IsInRole(roleName);
    else
        return false;
}

3)次に、これら2つのクラスをweb.configにプラグインしました。

<membership defaultProvider="FirstlookMemberProvider" userIsOnlineTimeWindow="15">
  <providers>
    <clear/>
    <add name="FirstlookMemberProvider" type="FirstlookAdmin.DomainEntities.FirstlookMemberProvider, FirstlookAdmin" />
  </providers>
</membership>
<roleManager defaultProvider="FirstlookRoleProvider" enabled="true" cacheRolesInCookie="true">
  <providers>
    <clear/>
    <add name="FirstlookRoleProvider" type="FirstlookAdmin.DomainEntities.FirstlookRoleProvider, FirstlookAdmin" />
  </providers>
</roleManager>

それでおしまい。デフォルトの許可アクションフィルターはこれらのクラスを使用します。ログインページのサインインとサインオフを処理する必要があります。通常のように、これには標準フォーム認証クラスを使用してください。

81
Matt Wrock

セキュリティ関連の何かが「簡単」だと誰かが言うときはいつでも、それらはほとんど常に間違っています。セキュリティには、専門家ではない人が見逃しがちな微妙な要素がたくさんあります。

特に、キャッシュを明示的に処理しない認証形式は本質的に破られます。アクション結果がキャッシュされると、これはASP.NET内で発生します。必ずしもASP.NET MVCスタック内にあるとは限りません。 AuthorizeAttributeのソースコードを調べると、アクションの結果がキャッシュされている場合でも、常に実行されるように、少しトリッキーで効果的なコードが含まれていることがわかります。

これまでのところ、ASP.NET MVC認証をカスタマイズする最善の方法は、カスタムASP.NETメンバーシッププロバイダーを作成することです これが絶対に確実であるとは主張しませんが、取得する方法は少ないですこのルートで壊れたセキュリティの実装に問題があり、次に他の方法に問題があります。この手法の大きな利点は、コードを変更せずに、ほとんどいつでも別の承認システムを代用できることです。

カスタムMVC属性を実装する必要がある場合は、スレッドの安全性に関するソースコード内のコメントに注意して、AuthorizeAttributeをサブタイプし、AuthorizeCoreをオーバーライドする必要があります。

11
Craig Stuntz

もちろんできます。メンバーシッププロバイダーを完全に無視して、プロジェクトでそれを行いました。

独自のActionFilterを実装する必要があります。基本的に、コントローラーのアクションがヒットする前に制御をインターセプトします。その内部で、アクションを続行するか、ユーザーをログインページにリダイレクトするかを決定します。

属性には、認証/承認モデルをサポートするために必要なパラメータを定義できます。

public class AuthorizationAttribute : ActionFilterAttribute, IActionFilter
{
   public MyRole UserRole { get; set; }

   void IActionFilter.OnActionExecuting (ActionExecutedContext filterContext)
   {
       // Decide whether to grant access to the action or redirect away
   }
}

[Authorization (UserRole = MyRole.All)]
public class UserController : Controller
{
    [Authorization (UserRole = MyRole.Admin)]
    public ActionResult Delete ()
    {
    }
}

コメントで表明された懸念について。はい、出力キャッシュを有効にすると、認証が妨げられます。ただそれを意識する必要があります。

問題の説明: ASP.NET MVCヒント#40-承認が必要なページをキャッシュしないでください

10
user151323

少なくとも2の可能性があります

  • 承認チェックを提供するカスタムアクションフィルター属性
  • ログインしたユーザー(ロールを含む)に必要なすべてのデータを入力し、既存のアクションフィルターを使用できるカスタムIHttpModule

2番目の選択肢は、通常のWebフォームでも使用できます。

1
Robert Koritnik