Asp.net web api ClaimsPrinciplePermission引发的自定义错误

Asp.net web api ClaimsPrinciplePermission引发的自定义错误,asp.net-web-api,claims-based-identity,jwt,Asp.net Web Api,Claims Based Identity,Jwt,我将基于声明的安全性与OAuth JWT承载令牌一起使用,并使用ClaimsPrincipalPermission属性修饰了我的web api操作方法,如下所示: [ClaimsPrincipalPermission(SecurityAction.Demand, Operation = "Admin", Resource = "DeleteUser")] [HttpPost] public IHttpActionResult Delete(string id) {

我将基于声明的安全性与OAuth JWT承载令牌一起使用,并使用ClaimsPrincipalPermission属性修饰了我的web api操作方法,如下所示:

    [ClaimsPrincipalPermission(SecurityAction.Demand, Operation = "Admin", Resource = "DeleteUser")]
    [HttpPost]
    public IHttpActionResult Delete(string id)
    {
        //code for getting user details based on id rcvd.
        ...
        ...
        return Ok("Dropped user:" + userName);
    }
这很有效。问题是,对于没有所需权限访问此web api方法的所有用户,我都会收到一个安全异常。这是一根非常难看的绳子,就像下面的那根

{
    "message": "An error has occurred.",
    "exceptionMessage": "ID4266: Request for ClaimsPrincipalPermission failed for: Action: 'System.Collections.ObjectModel.Collection`1[System.Security.Claims.Claim]', Resource: 'System.Collections.ObjectModel.Collection`1[System.Security.Claims.Claim]'.",
    "exceptionType": "System.Security.SecurityException",
    "stackTrace": "   at System.IdentityModel.Services.ClaimsPrincipalPermission.Demand()\r\n   at System.Security.PermissionSet.DemandNonCAS()\r\n   at TheService.Controllers.SampleController.Drop(String id) in d:\\Entire\\path\\to\\source\\code\\here\\SampleController.cs:line 37\r\n   at lambda_method(Closure , Object , Object[] )\r\n   at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass10.<GetExecutor>b__9(Object instance, Object[] methodParameters)\r\n   at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Execute(Object instance, Object[] arguments)\r\n   at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary`2 arguments, CancellationToken cancellationToken)\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()\r\n   at System.Web.Http.Controllers.ApiControllerActionInvoker.<InvokeActionAsyncCore>d__0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()\r\n   at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__2.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()\r\n   at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()"
}
关于如何做到这一点有什么建议吗

public class GlobalSecurityExceptionFilter : ExceptionFilterAttribute
    {        public override void OnException(HttpActionExecutedContext actionExecutedContext)
        {
            var exceptionType = actionExecutedContext.Exception.GetType();
            if (exceptionType == typeof (SecurityException))
            {
                actionExecutedContext.Response = ActionExecutedContext.Request.CreateErrorResponse(HttpStatusCode.Forbidden,JsonConvert.SerializeObject(new { message = "not enough privileges.", err_type="Security Issue", err_code = "Some custom error code here"}));
            }
            base.OnException(actionExecutedContext);
        }
    }
然后在webapi.config中:

    public static void Register(HttpConfiguration config)
        {
           config.Filters.Add(new GlobalSecurityExceptionFilter());
您可能还希望从ClaimsPrincipalPerpermission中提取一些属性:

var claimsPermissionAttrType = typeof (ClaimsPrincipalPermissionAttribute);
var stackTrace = new StackTrace(e);
for (int i=0; i<stackTrace.FrameCount; i++)
        {
            var attribute = stackTrace.GetFrame(i).GetMethod().GetCustomAttributes(claimsPermissionAttrType, false).FirstOrDefault();
            if (attribute == null) continue;
            var attr = (ClaimsPrincipalPermissionAttribute) attribute;
            return new SecurityException(string.Format("Security check failed. Principal = {3}, Action = {0}, Operation={1}, Resource={2}\n", 
                attr.Action, attr.Operation, attr.Resource, ClaimsPrincipal.Current.Identity.Name), e);
        }
不说实话

var claimsPermissionAttrType = typeof (ClaimsPrincipalPermissionAttribute);
var stackTrace = new StackTrace(e);
for (int i=0; i<stackTrace.FrameCount; i++)
        {
            var attribute = stackTrace.GetFrame(i).GetMethod().GetCustomAttributes(claimsPermissionAttrType, false).FirstOrDefault();
            if (attribute == null) continue;
            var attr = (ClaimsPrincipalPermissionAttribute) attribute;
            return new SecurityException(string.Format("Security check failed. Principal = {3}, Action = {0}, Operation={1}, Resource={2}\n", 
                attr.Action, attr.Operation, attr.Resource, ClaimsPrincipal.Current.Identity.Name), e);
        }