これは私をしばらく困惑させました。一般的に遭遇する同様の状況のどれも明らかにここに当てはまるようには見えません。私はおそらく明らかな何かを見逃しましたが、それを見ることができません。
Mvc Webアプリケーションでは、AuthorizeおよびAllowAnonymous属性を使用して、サイトのセキュリティで保護された領域をロックダウンするのではなく、公開されているアクションを明示的に開く必要があります。私はそのアプローチを好む。ただし、WebAPIで同じ動作をすることはできません。
System.Web.Http.AuthorizeAttributeから継承するカスタム認証属性を次のように作成しました。
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class MyAuthorizationAttribute : System.Web.Http.AuthorizeAttribute
これをフィルターとして登録しました:
public static void RegisterHttpFilters(HttpFilterCollection filters)
{
filters.Add(new MyAuthorizationAttribute());
}
これはすべて期待どおりに機能し、アクションは資格情報なしでは使用できなくなりました。問題は、次のメソッドではAllowAnonymous属性がそれを実行できないことです。
[System.Web.Http.AllowAnonymous]
public class HomeController : ApiController
{
[GET("/"), System.Web.Http.HttpGet]
public Link[] Index()
{
return new Link[]
{
new SelfLink(Request.RequestUri.AbsoluteUri, "api-root"),
new Link(LinkRelConstants.AuthorizationEndpoint, "OAuth/Authorize/", "authenticate"),
new Link(LinkRelConstants.AuthorizationTokenEndpoint , "OAuth/Tokens/", "auth-token-endpoint")
};
}
}
最も一般的なシナリオは、2つのAuthorize/AllowAnonymous属性を混在させることです。 System.Web.MvcはWebアプリ用で、System.Web.HttpはWebAPI用です(とにかく理解しています)。
私が使用している属性は両方とも同じ名前空間-System.Web.Httpからのものです。これは基本機能を継承するだけで、OnAuthotizeメソッドに必要なコードを挿入できると想定しました。
ドキュメントによると、AllowAnonymous属性は、すぐに呼び出すOnAuthorizeメソッド内で機能します。
public override void OnAuthorization(HttpActionContext actionContext)
{
base.OnAuthorization(actionContext);
どんな考えでも本当に感謝されるでしょう。
誰もが以前にこの問題に遭遇し、根本原因を見つけましたか?
AuthorizeAttributeには次のコードがあります。
private static bool SkipAuthorization(HttpActionContext actionContext)
{
Contract.Assert(actionContext != null);
return actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any()
|| actionContext.ControllerContext.ControllerDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any();
}
このメソッドをAuthorizeAttributeクラスに含めてから、OnAuthorizationメソッドの先頭に次を追加して、AllowAnonymous属性が見つかった場合に承認をスキップします。
if (SkipAuthorization(actionContext)) return;
ASP.NET MVC 4:
bool skipAuthorization = filterContext.ActionDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true)
|| filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true);
または
private static bool SkipAuthorization(AuthorizationContext filterContext)
{
Contract.Assert(filterContext != null);
return filterContext.ActionDescriptor.GetCustomAttributes(typeof(AllowAnonymousAttribute), true).Any()
|| filterContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes(typeof(AllowAnonymousAttribute), true).Any();
}
C#6.0の使用ActionExecutingContextを拡張する静的クラスを作成します。
public static class AuthorizationContextExtensions {
public static bool SkipAuthorization(this ActionExecutingContext filterContext) {
Contract.Assert(filterContext != null);
return filterContext.ActionDescriptor.GetCustomAttributes(typeof(AllowAnonymousAttribute), true).Any()|| filterContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes(typeof(AllowAnonymousAttribute), true).Any();
}
}
これで、オーバーライドfilterContextが拡張メソッドを呼び出すことができ、それらが同じ名前空間にあることを確認するか、適切なusingステートメントを含めるだけです。
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class AuthorizeCustomAttribute : ActionFilterAttribute {
public override void OnActionExecuting(ActionExecutingContext filterContext) {
if (filterContext.SkipAuthorization()) return;// CALL EXTENSION METHOD
/*NOW DO YOUR LOGIC FOR NON ANON ACCESS*/
}
}
私は別のバージョンの.netフレームワークまたはWeb APIを使用する必要がありますが、うまくいけば、これは誰かを助ける:
bool skipAuthorization = actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any() || actionContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any();
if (skipAuthorization)
{
return;
}
MVC 5を使用する
この問題を解決する手順:-
1。 WebAPIプロジェクトの匿名属性を更新し、次のようにします
[System.Web.Mvc.AllowAnonymous]
次に、カスタム属性クラスに移動してコードを記述します
public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext filterContext)
{
if (filterContext == null)
{
throw new UnauthorizedAccessException("Access Token Required");
}
base.OnAuthorization(filterContext);
if (filterContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any())
{
return;
}
if (filterContext.Request.Headers.Authorization != null)
{
var response =
PTPRestClient.GetRequest(filterContext.Request.Headers.Authorization.ToString(),
"api/validate/validate-request");
if (!response.IsSuccessStatusCode)
{
throw new UnauthorizedAccessException();
}
}
else
{
throw new UnauthorizedAccessException("Access Token Required");
}
}
public class MyAuthorizationAuthorize : AuthorizeAttribute, IAuthorizationFilter
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext.HttpContext.Request.IsAuthenticated)
{
bool skipAuthorization = filterContext.ActionDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true) ||
filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true);
if (skipAuthorization) return;
}
else filterContext.Result = new HttpUnauthorizedResult();
}
}