我正在通过自定义操作过滤器为我的MVC应用程序实现授权机制。
我提供了以下自定义操作过滤器以进行授权:
[AttributeUsageAttribute(AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class AuthorizationFilterAttribute : ActionFilterAttribute
{
public AuthorizationEntity Entity { get; set; }
public AuthorizationPermission Permission { get; set; }
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
AuthorizationResult result = null;
// Base actions (Authentication first)
base.OnActionExecuting(filterContext);
BaseController controller = filterContext.Controller as BaseController;
if (controller != null)
{ // Base actions (Authorizatioın next)
User usr = controller.currentUser;
AuthorizationResult ar = AuthorizationManager.GetAuthorizationResult(this.Entity, this.Permission, usr.UserId, usr.RoleId);
if (!ar.IsAuthorized)
{
throw new UnauthorizedAccessException(ar.Description);
}
// Authorized, continue
return;
}
}
}
在我的Base Controller类中,我正在处理 UnauthorizedAccessException 类型的例外,并通过以下代码将它们重定向到警告页面
protected override void OnException(ExceptionContext filterContext)
{
if (filterContext.Exception is UnauthorizedAccessException)
{
if (!filterContext.HttpContext.Request.IsAjaxRequest())
{
Exception ex = filterContext.Exception;
filterContext.ExceptionHandled = true;
filterContext.Result = new ViewResult()
{
ViewName = "UnauthorizedAccess"
};
}
else
{
throw filterContext.Exception;
}
}
}
此机制适用于返回 ActionResult 的操作。但是我也有一些AJAX调用,我不想重定向到警告页面但是会显示警告弹出窗口。这就是我检查请求是否是Ajax调用的原因。
我使用以下代码进行Ajax调用:
$.ajax({
type: "POST",
url: "AjaxPostMethodName",
dataType: "json",
data:
{
postval: [some value here]
},
success: function (msg) {
// Do some good actions here
},
error: function (x, t, m, b) {
// Display error
alert(m);
}
})
在Controller
上转到以下方法public JsonResult AjaxPostMethodName(string postval)
{
try
{
// Some cool stuff here
return Json(null);
}
catch (Exception ex)
{
Response.StatusCode = UNAUTHORIZED_ACCESS_HTTP_STATUS_CODE;
return Json(ex.Message);
}
}
但是当我未通过授权检查时,它会直接显示"内部服务器错误"消息而不是落入 AjaxPostMethodName 方法的catch块并显示正确的消息。
如何使此类代码显示 filterContext.Exception 而不是静态" 内部服务器错误"消息?
问候。
答案 0 :(得分:1)
我终于在另一个Stack Overflow帖子(Can I return custom error from JsonResult to jQuery ajax error method?)中找到了我的解决方案的答案。我应该使用 JsonExceptionFilterAttribute ,如下所示:
public class JsonExceptionFilterAttribute : FilterAttribute, IExceptionFilter
{
public void OnException(ExceptionContext filterContext)
{
if (filterContext.RequestContext.HttpContext.Request.IsAjaxRequest())
{
filterContext.HttpContext.Response.StatusCode = 500;
filterContext.ExceptionHandled = true;
string msg = filterContext.Exception.Message;
if (filterContext.Exception.GetType() == Type.GetType("System.UnauthorizedAccessException"))
{
msg = "Unauthorized access";
}
filterContext.Result = new JsonResult
{
Data = new
{
errorMessage = msg
},
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
}
}
}
答案 1 :(得分:0)
当您的代码中存在未处理的异常时,将调用您的OnException
方法。在您的ajax方法AjaxPostMethodName
中,您已将代码放在try catch
blcok中。因此,此方法中的任何异常都不会转到OnException
方法。
答案 2 :(得分:0)
我刚刚检查了Response.StatusCode行为,对我来说它有效。
Index.cshtml
@{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<script type="text/javascript">
$(document).ready(function () {
alert('doc ready');
$.ajax({
type: "POST",
url: '@Url.Action("AjaxPostMethodName")',
dataType: "json",
data:
{
test: '10'
},
success: function (msg) {
// Do some good actions here
alert('success');
alert(msg);
},
error: function (x, t, m, b) {
// Display error
alert('error');
}
});
});
</script>
HomeController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace MvcApplication1.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
[HttpPost]
public JsonResult AjaxPostMethodName(string postval)
{
Response.StatusCode = 401;
return Json("test");
}
}
}
当我将Response.StatusCode设置为200时,它调用成功,当401调用error时。
请验证代码的其他部分是否不会以某种方式干扰它。
你也可以尝试下面的解决方法 - 如果AjaxPostMethodName抛出异常返回JSON有一个标志isValid和一条消息errorMessage,所以在你的ajax成功方法中你可以检查isValid是否正常并处理错误。