是否可以通过编程方式测试当前用户是否能够访问给定路径?这将是我需要限制访问的某个资源的路径,它将是一个通过处理程序而不是直接通过其路径访问的资源。
例如,给定以下配置设置:
<authentication mode="Forms">
<forms loginUrl="~/login/" defaultUrl="~/private/" protection="All" cookieless="UseCookies" slidingExpiration="true" path="/" />
</authentication>
...
<location path="private">
<system.web>
<authorization>
<deny users="?" />
<allow users="*" />
</authorization>
</system.web>
</location>
<location path="private/general">
<system.web>
<authorization>
<allow roles="general" />
<deny users="*" />
</authorization>
</system.web>
</location>
我们可以这样做吗?:
HttpContext.Current.User.Identity.IsAllowedToAccess("~/private/general/my-resource")
哪些会为“普通”角色中的用户返回true
,为其他任何人返回false
?
请注意,配置设置只是一个示例 - 可能会有更多的位置定义和角色等,因此使用大量myPath.StartsWith("/private/")
语句进行测试并不是一个很好的解决方案。
答案 0 :(得分:0)
我从来没有完全理解这一点,所以我不得不稍微改变一下方法。
这假设我们尝试获取的资源通常不会由IIS提供 - 在我的情况下,这是Web表单用户控件(.ascx),我想要的通过Ajax获取,呈现为一个字符串,然后可以通过JavaScript在HTML中的某个地方注入。
我摆脱了处理程序,而是将其设置为使得对这些资源的任何请求都直接发送到资源,但稍微修改了.ascx.asmx扩展名。例如,/private/general/my-resource.ascx.asmx
。
然后我添加了一个HTTP模块(集成管道模式):
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<add name="MyResourceHttpModule" type="MyApp.Controls.MyResourceHttpModule" />
</modules>
</system.webServer>
(或经典的管道模式):
<system.web>
<httpModules>
<add name="MyResourceHttpModule" type="MyApp.Controls.MyResourceHttpModule" />
</httpModules>
</system.web>
相关代码:
using System;
using System.Web;
namespace MyApp.Controls
{
public class MyResourceHttpModule : IHttpModule
{
#region IHttpModule Members
public void Dispose()
{
}
public void Init(HttpApplication context)
{
context.AuthorizeRequest += new EventHandler(OnAuthorizeRequest);
}
#endregion
void OnAuthorizeRequest(object sender, EventArgs e)
{
var application = (HttpApplication)sender;
if (application.Context.Request.Url.AbsolutePath.EndsWith(".ascx.asmx"))
{
application.Context.RewritePath("~/Services/MyResource.asmx/GetResource");
}
}
}
}
此模块将请求的URL重写为Web服务(MyResource.asmx),然后剥离我们最初添加的额外扩展,最后提供我们尝试访问的文件(在本例中为web表单用户控件):
using System.Collections.Generic;
using System.Web;
using System.Web.Script.Services;
using System.Web.Services;
using System.Web.UI;
namespace MyApp.Services
{
[ScriptService]
public class MyResource : System.Web.Services.WebService
{
[WebMethod(EnableSession = true)]
public object GetResource()
{
var controlPath = HttpContext.Current.Request.RawUrl;
if (Paths.ApplicationPath != "" && controlPath.StartsWith(Paths.ApplicationPath)) controlPath = '~' + controlPath.Substring(Paths.ApplicationPath.Length);
if (controlPath.EndsWith(".asmx")) controlPath = controlPath.Substring(0, controlPath.Length - 5);
using (var myUserControl = (MyApp.Controls.MyUserControl)(new Page()).LoadControl(controlPath))
{
myUserControl.DataBind();
return myUserControl.RenderToString();
}
}
}
}
(这使用此RenderToString扩展方法):
public static string RenderToString(this System.Web.UI.Control control)
{
var stringBuilder = new StringBuilder();
using (var stringWriter = new StringWriter(stringBuilder))
{
using (var htmlTextWriter = new System.Web.UI.HtmlTextWriter(stringWriter))
{
control.RenderControl(htmlTextWriter);
return stringBuilder.ToString();
}
}
}
这一切都有效,因为表单身份验证在允许请求之前通过web.config中设置的授权规则运行,因此我们知道,当它到达我们的HTTP模块时,可以提供所请求的文件,因为当前用户必须有权访问该路径。