6

新しいWebAPIベータ版を使用しようとしているWebフォームアプリケーションがあります。私が公開しているエンドポイントは、AJAXで使用するため、サイトの認証されたユーザーのみが利用できるようにする必要があります。私のweb.configでは、認証されていない限り、すべてのユーザーを拒否するように設定しています。これは、Webフォームでは正常に機能しますが、MVCまたはWebAPIでは期待どおりに機能しません。

テストするMVCコントローラーとWebAPIコントローラーの両方を作成しました。私が見ているのは、認証するまでMVCまたはWeb APIエンドポイントにアクセスできないことですが、その後、ブラウザーを閉じてアプリプールをリサイクルした後でも、これらのエンドポイントにアクセスし続けることができます。しかし、aspxページの1つにアクセスすると、ログインページに戻ります。再度認証するまで、MVCまたはWebAPIエンドポイントにアクセスできません。

セッションが無効になるとASPXページが機能するため、MVCとWeb APIが機能しない理由はありますか?見た目では、ASPXリクエストのみがフォーム認証Cookieをクリアしています。これが、ここでの問題であると想定しています。

4

3 に答える 3

3

Web API が既存の MVC アプリケーション内で使用されているだけの場合はAuthorizeAttribute、MVC と WebApi コントローラーの両方にカスタム フィルターを作成することをお勧めします。私が「AuthorizeSafe」フィルターと呼んでいるものを作成します。これは、デフォルトですべてをブラックリストに登録するため、コントローラーまたはメソッドに認証属性を適用するのを忘れると、アクセスが拒否されます (デフォルトのホワイトリスト アプローチは安全ではないと思います)。

拡張用に 2 つの属性クラスが用意されています。System.Web.Mvc.AuthorizeAttributeそしてSystem.Web.Http.AuthorizeAttribute; 前者は MVC フォーム認証で使用され、後者はフォーム認証にもフックされます (これは、API 認証と承認のためにまったく別の認証アーキテクチャを構築する必要がないことを意味するため、非常に便利です)。これが私が思いついたものです-AllowAnonymousまたはAuthorizeSafe属性が適用されない限り、デフォルトですべてのMVCコントローラー/アクションおよびWebApiコントローラー/アクションへのアクセスを拒否します。まず、カスタム属性を支援する拡張メソッド:

public static class CustomAttributeProviderExtensions {
    public static List<T> GetCustomAttributes<T>(this ICustomAttributeProvider provider, bool inherit) where T : Attribute {
        List<T> attrs = new List<T>();

        foreach (object attr in provider.GetCustomAttributes(typeof(T), false)) {
            if (attr is T) {
                attrs.Add(attr as T);
            }
        }

        return attrs;
    }
}

AuthorizeAttribute両方の拡張機能が使用する承認ヘルパー クラス:

public static class AuthorizeSafeHelper {
    public static AuthActionToTake DoSafeAuthorization(bool anyAllowAnonymousOnAction, bool anyAllowAnonymousOnController, List<AuthorizeSafeAttribute> authorizeSafeOnAction, List<AuthorizeSafeAttribute> authorizeSafeOnController, out string rolesString) {
        rolesString = null;

        // If AllowAnonymousAttribute applied to action or controller, skip authorization
        if (anyAllowAnonymousOnAction || anyAllowAnonymousOnController) {
            return AuthActionToTake.SkipAuthorization;
        }

        bool foundRoles = false;
        if (authorizeSafeOnAction.Count > 0) {
            AuthorizeSafeAttribute foundAttr = (AuthorizeSafeAttribute)(authorizeSafeOnAction.First());
            foundRoles = true;
            rolesString = foundAttr.Roles;
        }
        else if (authorizeSafeOnController.Count > 0) {
            AuthorizeSafeAttribute foundAttr = (AuthorizeSafeAttribute)(authorizeSafeOnController.First());
            foundRoles = true;
            rolesString = foundAttr.Roles;
        }

        if (foundRoles && !string.IsNullOrWhiteSpace(rolesString)) {
            // Found valid roles string; use it as our own Roles property and auth normally
            return AuthActionToTake.NormalAuthorization;
        }
        else {
            // Didn't find valid roles string; DENY all access by default
            return AuthActionToTake.Unauthorized;
        }
    }
}

public enum AuthActionToTake {
    SkipAuthorization,
    NormalAuthorization,
    Unauthorized,
}

2 つの拡張クラス自体:

public sealed class AuthorizeSafeFilter : System.Web.Mvc.AuthorizeAttribute {
    public override void OnAuthorization(AuthorizationContext filterContext) {
        if (!string.IsNullOrEmpty(this.Roles) || !string.IsNullOrEmpty(this.Users)) {
            throw new Exception("This class is intended to be applied to an MVC web API application as a global filter in RegisterWebApiFilters, not applied to individual actions/controllers.  Use the AuthorizeSafeAttribute with individual actions/controllers.");
        }

        string rolesString;
        AuthActionToTake action = AuthorizeSafeHelper.DoSafeAuthorization(
            filterContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>(false).Count() > 0,
            filterContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes<AllowAnonymousAttribute>(false).Count() > 0,
            filterContext.ActionDescriptor.GetCustomAttributes<AuthorizeSafeAttribute>(false),
            filterContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes<AuthorizeSafeAttribute>(false),
            out rolesString
        );

        string rolesBackup = this.Roles;
        try {
            switch (action) {
                case AuthActionToTake.SkipAuthorization:
                    return;

                case AuthActionToTake.NormalAuthorization:
                    this.Roles = rolesString;
                    base.OnAuthorization(filterContext);
                    return;

                case AuthActionToTake.Unauthorized:
                    filterContext.Result = new HttpUnauthorizedResult();
                    return;
            }
        }
        finally {
            this.Roles = rolesBackup;
        }
    }
}

public sealed class AuthorizeSafeApiFilter : System.Web.Http.AuthorizeAttribute {
    public override void OnAuthorization(HttpActionContext actionContext) {
        if (!string.IsNullOrEmpty(this.Roles) || !string.IsNullOrEmpty(this.Users)) {
            throw new Exception("This class is intended to be applied to an MVC web API application as a global filter in RegisterWebApiFilters, not applied to individual actions/controllers.  Use the AuthorizeSafeAttribute with individual actions/controllers.");
        }

        string rolesString;
        AuthActionToTake action = AuthorizeSafeHelper.DoSafeAuthorization(
            actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Count > 0,
            actionContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Count > 0,
            actionContext.ActionDescriptor.GetCustomAttributes<AuthorizeSafeAttribute>().ToList(),
            actionContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes<AuthorizeSafeAttribute>().ToList(),
            out rolesString
        );

        string rolesBackup = this.Roles;
        try {
            switch (action) {
                case AuthActionToTake.SkipAuthorization:
                    return;

                case AuthActionToTake.NormalAuthorization:
                    this.Roles = rolesString;
                    base.OnAuthorization(actionContext);
                    return;

                case AuthActionToTake.Unauthorized:
                    HttpRequestMessage request = actionContext.Request;
                    actionContext.Response = request.CreateResponse(HttpStatusCode.Unauthorized);
                    return;
            }
        }
        finally {
            this.Roles = rolesBackup;
        }
    }
}

そして最後に、特定のロールのユーザーがアクセスできるようにするためにメソッド/コントローラーに適用できる属性:

public class AuthorizeSafeAttribute : Attribute {
    public string Roles { get; set; }
}

次に、"AuthorizeSafe" フィルターを Global.asax からグローバルに登録します。

    public static void RegisterGlobalFilters(GlobalFilterCollection filters) {
        // Make everything require authorization by default (whitelist approach)
        filters.Add(new AuthorizeSafeFilter());
    }

    public static void RegisterWebApiFilters(HttpFilterCollection filters) {
        // Make everything require authorization by default (whitelist approach)
        filters.Add(new AuthorizeSafeApiFilter());
    }

次に、アクションを開きます。匿名アクセスまたは管理者アクセスのみ:

public class AccountController : System.Web.Mvc.Controller {
    // GET: /Account/Login
    [AllowAnonymous]
    public ActionResult Login(string returnUrl) {
        // ...
    }
}

public class TestApiController : System.Web.Http.ApiController {
    // GET API/TestApi
    [AuthorizeSafe(Roles="Admin")]
    public IEnumerable<TestModel> Get() {
        return new TestModel[] {
            new TestModel { TestId = 123, TestValue = "Model for ID 123" },
            new TestModel { TestId = 234, TestValue = "Model for ID 234" },
            new TestModel { TestId = 345, TestValue = "Model for ID 345" }
        };
    }
}
于 2012-11-12T14:52:02.963 に答える
1

通常の MVC コントローラーで動作するはずです。アクションを [Authorize] 属性で装飾するだけです。

Web API では、カスタム承認が必要です。以下のリンクが役立つ場合があります。

http://www.codeproject.com/Tips/376810/ASP-NET-WEB-API-Custom-Authorize-and-Exception-Han

于 2012-05-04T05:27:50.343 に答える
-1

MVC Authorize 属性を使用している場合、通常の MVC コントローラーと同じように WebAPI に対して機能するはずです。

于 2012-04-26T10:39:14.690 に答える