自定义ClaimsPrinciplePermission抛出的错误

时间:2015-04-20 09:48:28

标签: 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)
    {
        //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()"
}

我希望将其格式化得更好,我只会发送错误消息,其中包含自定义错误字符串和数字,如下所示:

{
        "message": "not enough privileges.",
        "err_type": "Security Issue",
        "err_code": "Some custom error code here"
}

有关如何完成此操作的任何提示?

1 个答案:

答案 0 :(得分:0)

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());

您可能还想从ClaimsPrincipalPermission中提取一些属性:

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);
        }

不诚实,不要提及this