我在ASP.NET中成功实现了基于角色的授权。当一个人没有所需的角色时,他会看到401.2未经授权的错误页面。
我现在想要完成的是在我的应用程序中有一个自定义的401页面,并通过web.config中的设置将其重定向到那里。我试过这个:
<customErrors mode="RemoteOnly" defaultRedirect="GenericErrorPage.htm">
<error statusCode="401" redirect="NoAccess.htm" />
</customErrors>
但这并没有被抓住。我是否必须在IIS中覆盖它?我希望不会因为这会使部署更加困难。
答案 0 :(得分:7)
我最近遇到了同样的问题,结果发现这是使用Windows身份验证时的一个怪癖。
Joshua Flanagan不久前创建了一个nice HttpModule,它将尊重web.config中的customErrors部分并重定向到401错误页面。
解决方案的关键是拦截页面生命周期的 EndRequest 事件,检查401状态代码,然后执行自定义页面。
HttpModule的可移植性很好,因为它使解决方案可以重复使用,并保持你的Global.asax干净,但是如果你真的想要的话,没有什么能阻止你用他的代码在Global.asax中连接你的EndRequest事件。
如果您使用的是ASP.NET MVC,那么解决方案就不那么优雅了。
答案 1 :(得分:3)
如果您不想添加HttpModule
web.config中的
<system.web>
<customErrors mode="On" defaultRedirect="~/MyController/MyErrorAction/" redirectMode="ResponseRedirect">
<error statusCode="401" redirect="~/MyController/MyErrorAction/" />
</customErrors>
在global.asax.cs
中 protected void Application_EndRequest(object sender, EventArgs e)
{
HttpApplication application = (HttpApplication)sender;
if (application.Response.StatusCode != 401 || !application.Request.IsAuthenticated) return;
application.Response.ClearContent();
//You can replace the piece below is to redirect using MVC, or your can replace all this with application.Server.Execute(yourPage);
IController errorController = new SharedController();
var rd = new RouteData();
rd.Values.Add("controller", "MyController");
rd.Values.Add("action", "MyErrorAction");
rd.Values.Add("value", "You or your user group do not have permissions to use the address: " + Request.Url.PathAndQuery);
errorController.Execute(new RequestContext(new HttpContextWrapper(Context), rd));
HttpContext.Current.Server.ClearError();
}
答案 2 :(得分:3)
这是一个MVC无关的变体:
在Web.config中
<customErrors mode="RemoteOnly" defaultRedirect="GenericErrorPage.htm">
<error statusCode="401" redirect="NoAccess.htm" />
</customErrors>
在Global.asax.cs
中protected void Application_EndRequest(object sender, EventArgs e)
{
HttpApplication application = (HttpApplication)sender;
if (application.Response.StatusCode != 401 || !application.Request.IsAuthenticated) return;
var customErrors = (CustomErrorsSection)ConfigurationManager.GetSection("system.web/customErrors");
var accessDeniedPath = customErrors.Errors["401"] != null ? customErrors.Errors["401"].Redirect : customErrors.DefaultRedirect;
if (string.IsNullOrEmpty(accessDeniedPath))
return; // Let other code handle it (probably IIS).
application.Response.ClearContent();
application.Server.Execute(accessDeniedPath);
HttpContext.Current.Server.ClearError();
}
答案 3 :(得分:1)
这对我来说效果很好。
Global.asax -
protected void Application_EndRequest(object sender, EventArgs e)
{
if (Response.StatusCode == 401 && Request.IsAuthenticated)
{
Response.StatusCode = 303;
Response.Clear();
Response.Redirect("~/AccessDenied.html");
Response.End();
}
}
Web.config -
<system.web>
<customErrors mode="On">
<error statusCode="401" redirect="AccessDenied.html"/>
</customErrors>
<authentication mode="Windows"/>
</system.web>
<location path="AccessDenied.html">
<system.web>
<authorization>
<allow roles="*"/>
</authorization>
</system.web>
</location>
<location path=".">
<system.web>
<authorization>
<allow roles="YourADGroup"/>
<deny users="*" />
</authorization>
</system.web>
</location>
这也会在200期之前处理双401。 还可以绕过讨厌的firefox身份验证弹出窗口。