web-dev-qa-db-ja.com

ASP.NET MVCでエリア全体に認可を設定するにはどうすればよいですか?

管理領域があり、管理者だけが領域に入ることを望みます。 AdminエリアのすべてのコントローラーにAuthorized属性を追加することを検討しました。エレガントなソリューションはありませんか、またはこの機能はフレームワーク自体にはありませんか?

編集:すみません、私はこれを前に言及する必要がありました。 AuthorizeAttributeから派生したカスタムAuthorizedAttributeを使用しています。

53

Web.configベースのセキュリティは、ほぼneverをMVCアプリケーションで使用する必要があります。これは、複数のURLがコントローラーにヒットする可能性があり、これらのチェックをWeb.configに入れると必ず何かを見逃すからです。覚えておいてください-コントローラーはエリアに関連付けられておらず、ルートはエリアに関連付けられています。 MVCコントローラーファクトリは、競合がない場合、エリア以外のリクエストに対してAreas /フォルダーからコントローラーを提供します。

たとえば、デフォルトのプロジェクト構造を使用して、AdminDefaultControllerで管理領域を追加すると、このコントローラーを/ Admin/AdminDefault/Indexand/ AdminDefaultでヒットできます。 /インデックス。

サポートされる唯一のソリューションは、コントローラーの基本クラスに属性を配置し、エリア内の各コントローラーがその基本クラスをサブクラス化することです。

53
Levi

私はちょうどこの同じ問題を調査しています。エリアに基づいてコントローラーを保護することはnot可能であるため、より単純なオプションが思い浮かびます。

コントローラーをオーバーライドする各エリアのベースコントローラー定義を作成し、これに必要なセキュリティを追加します。次に、エリア内の各コントローラーがControllerではなくAreaControllerをオーバーライドすることを確認する必要があります。例えば:

/// <summary>
/// Base controller for all Admin area
/// </summary>
[Authorize(Roles = "Admin")]
public abstract class AdminController : Controller { }

このベースから管理領域の各コントローラーを派生させる必要がありますが、

public class HomeController : AdminController
{
    // .. actions
}

ただし、少なくとも、エリアのセキュリティを定義する単一のポイントがあります。

45
Quango

私はこれに着手しました...しかし、これまでのところ、これは私にとってかなりうまく機能しています。

カスタムAuthorizeAttributeクラスを作成し、RegisterGlobalFilters関数に追加します。

CustomAuthorizeAttributeでは、それが存在するエリアに基づいてさまざまな条件をチェックします。

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new CustomAuthorizeAttribute());
        filters.Add(new HandleErrorAttribute());
    }
}

public class CustomAuthorizeAttribute : AuthorizeAttribute
{
    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        var routeData = httpContext.Request.RequestContext.RouteData;
        var controller = routeData.GetRequiredString("controller");
        var action = routeData.GetRequiredString("action");
        var area = routeData.DataTokens["area"];
        var user = httpContext.User;
        if (area != null && area.ToString() == "Customer")
        {
            if (!user.Identity.IsAuthenticated)
                return false;
        }
        else if (area != null && area.ToString() == "Admin")
        {
            if (!user.Identity.IsAuthenticated)
                return false;
            if (!user.IsInRole("Admin"))
                return false;
        }
        return true;
    }
}
14
Brian Rice

すべての管理コードが1つのコントローラーにある場合、クラス全体にAuthorizeを追加します。

[Authorize]
public class AdminController : Controller
{
     .......
}
13
John

開発者がalwaysを行う必要があるため、現在受け入れられている答えは最も安全なソリューションではありません。新しいコントローラまたはアクションの新しい基本クラスを継承することを忘れないでください(「ブラックリスト」。手動で制限されています)。これは特に、あなたの儀式に精通していない新しい開発者がプロ​​ジェクトに導入されるときに問題を引き起こします。特に数週間、数か月、または数年にわたってプロジェクトから目を離した後は、適切なコントローラークラスを継承することを忘れることは簡単です。開発者が継承を忘れた場合、プロジェクトにセキュリティの脆弱性があることは明らかではありません。

この問題に対するより安全なソリューションは、allリクエストへのアクセスを拒否し、アクションへのアクセスを許可されたロールで各アクションを修飾することです(「ホワイトリスト」。手動で許可されない限り、すべてのユーザーへのアクセスを防止します) 。開発者が適切な承認をホワイトリストに登録するのを忘れた場合、ユーザーに通知されます。適切なアクセスを許可する方法について他のコントローラーを確認するのと同じくらい簡単です。ただし、少なくとも重大なセキュリティ上の脆弱性はありません。

App_Start/FilterConfig.csファイルで、FilterConfigクラスを変更します。

_public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        ...

        //Deny access to all controllers and actions so that only logged in Administrators can access them by default
        filters.Add(new System.Web.Mvc.AuthorizeAttribute() { Roles = "Administrator" });
    }
_

これにより、ユーザーが管理者としてログインしていない限り、すべてのアクションにアクセスできなくなります。次に、異なる許可ユーザーがアクセスできるようにするアクションごとに、単に_[OverrideAuthorization]_および_[Authorize]_で装飾します。

これにより、ビジネスロジックでは、権限のないユーザーが機能にアクセスすることを心配することなく、さまざまな方法でAuthorize属性を使用できます。以下に例を示します。

例1-ログインしているAdministratorおよびDispatcherユーザーのみがIndex() GetおよびPostメソッドにアクセスできます。

_public class MarkupCalculatorController : Controller //Just continue using the default Controller class.
{
    // GET: MarkupCalculator
    [OverrideAuthorization]
    [Authorize(Roles = "Administrator,Dispatcher")]
    public ActionResult Index()
    {
        //Business logic here.

        return View(...);
    }

    // POST: DeliveryFeeCalculator
    [HttpPost]
    [ValidateAntiForgeryToken]
    [OverrideAuthorization]
    [Authorize(Roles = "Administrator,Dispatcher")]
    public ActionResult Index([Bind(Include = "Price,MarkedupPrice")] MarkupCalculatorVM markupCalculatorVM)
    {
        //Business logic here.

        return View(...);
    }
}
_

例2-認証されたユーザーのみがHomeコントローラーのIndex()メソッドへのアクセスを許可されます。

_public class HomeController : Controller
{
    [OverrideAuthorization]
    [Authorize] //Allow all authorized (logged in) users to use this action
    public ActionResult Index()
    {
        return View();
    }

}
_

-認証されていないユーザー(つまり匿名ユーザー)は、_[AllowAnonymous]_属性を使用してメソッドにアクセスすることができます。また、これは_[OverrideAuthorization]_属性を必要とせずに自動的にグローバルフィルターをオーバーライドします。

_    // GET: /Account/Login
    [AllowAnonymous]
    public ActionResult Login(string returnUrl)
    {
        ViewBag.ReturnUrl = returnUrl;
        return View();
    }

    //
    // POST: /Account/Login
    [HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
    {
        ...
    }
_

例4-管理者のみが_[Authorize]_属性を持たないメソッドへのアクセスを許可されます。

_public class LocationsController : Controller
{

    // GET: Locations
    public ActionResult Index()
    {
        //Business logic here.
        return View(...);
    }
}
_

注意事項

特定のアクションへのアクセスを特定のロールに制限する場合は、_[OverrideAuthorization]_属性を使用する必要があります。そうしないと、グローバルフィルターのために他のロール(例:Dispatcherなど)を指定しても、_[Authorize]_属性プロパティは無視され、デフォルトのロール(この例では管理者)のみが許可されます。権限のないユーザーはログイン画面にリダイレクトされます。

_[OverrideAuthorization]_属性を使用すると、アクションは設定したグローバルフィルターを無視します。そのため、オーバーライドを使用するたびに_[Authorize]_属性をmustに再適用して、アクションが安全に保たれるようにします。

エリアとコントローラー全体について

領域ごとに制限するには、要求しているように、個々のアクションの代わりに_[OverrideAuthorization]_および_[Authorize]_属性をコントローラーに配置します。

5
aiwyn