Asp.net mvc &引用;“安全意识”;行动链接?
如何创建“安全感知”操作链接,检测用户是否有权单击(调用)该操作?Asp.net mvc &引用;“安全意识”;行动链接?,asp.net-mvc,model-view-controller,security,Asp.net Mvc,Model View Controller,Security,如何创建“安全感知”操作链接,检测用户是否有权单击(调用)该操作? 如果不允许用户使用该操作,则隐藏链接 依靠 web.config(授权)和 [授权]操作的属性 PS 我想在MVC中混用这两种代码是不好的做法?这是从MvcSitemap项目中挖出的一些代码,并为我自己的使用进行了修改。如果我没记错的话,这段代码已经针对MVC2进行了修改,一些函数可能需要重新移植到MVC1 将MVC和FormsAuthentication混合在一起是一种不错的做法,MVC的默认身份验证方法是围绕现有的Asp
如果不允许用户使用该操作,则隐藏链接 依靠
- web.config(授权)和
- [授权]操作的属性
我想在MVC中混用这两种代码是不好的做法?这是从MvcSitemap项目中挖出的一些代码,并为我自己的使用进行了修改。如果我没记错的话,这段代码已经针对MVC2进行了修改,一些函数可能需要重新移植到MVC1 将MVC和FormsAuthentication混合在一起是一种不错的做法,MVC的默认身份验证方法是围绕现有的Asp.net安全基础架构构建的 确定用户是否具有权限的代码:
public static class SecurityTrimmingExtensions
{
public static bool HasActionPermission( this HtmlHelper htmlHelper, string actionName, string controllerName )
{
//if the controller name is empty the ASP.NET convention is:
//"we are linking to a different controller
ControllerBase controllerToLinkTo = string.IsNullOrEmpty(controllerName)
? htmlHelper.ViewContext.Controller
: GetControllerByName(htmlHelper, controllerName);
var controllerContext = new ControllerContext(htmlHelper.ViewContext.RequestContext, controllerToLinkTo);
var controllerDescriptor = new ReflectedControllerDescriptor(controllerToLinkTo.GetType());
var actionDescriptor = controllerDescriptor.FindAction(controllerContext, actionName);
return ActionIsAuthorized(controllerContext, actionDescriptor);
}
private static bool ActionIsAuthorized(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
{
if (actionDescriptor == null)
return false; // action does not exist so say yes - should we authorise this?!
AuthorizationContext authContext = new AuthorizationContext(controllerContext);
// run each auth filter until on fails
// performance could be improved by some caching
foreach (IAuthorizationFilter authFilter in actionDescriptor.GetFilters().AuthorizationFilters)
{
authFilter.OnAuthorization(authContext);
if (authContext.Result != null)
return false;
}
return true;
}
private static ControllerBase GetControllerByName(HtmlHelper helper, string controllerName)
{
// Instantiate the controller and call Execute
IControllerFactory factory = ControllerBuilder.Current.GetControllerFactory();
IController controller = factory.CreateController(helper.ViewContext.RequestContext, controllerName);
if (controller == null)
{
throw new InvalidOperationException(
String.Format(
CultureInfo.CurrentUICulture,
"Controller factory {0} controller {1} returned null",
factory.GetType(),
controllerName));
}
return (ControllerBase)controller;
}
}
Html帮助程序
public static class SecurityTrimmedLink
{
public static MvcHtmlString SecurityTrimmedActionLink(this HtmlHelper htmlHelper, string linkName, string actionName)
{
return htmlHelper.HasActionPermission(actionName, "")
? htmlHelper.ActionLink(linkName, actionName)
: MvcHtmlString.Create("");
}
public static MvcHtmlString SecurityTrimmedActionLink(this HtmlHelper htmlHelper, string linkName, string actionName, RouteValueDictionary routeValueDictionary )
{
return htmlHelper.HasActionPermission(actionName, "")
? htmlHelper.ActionLink(linkName, actionName, routeValueDictionary)
: MvcHtmlString.Create("");
}
public static MvcHtmlString SecurityTrimmedActionLink(this HtmlHelper htmlHelper, string linkName, string actionName, object routeValues, object htmlAttributes )
{
return htmlHelper.HasActionPermission(actionName, "")
? htmlHelper.ActionLink(linkName, actionName, routeValues, htmlAttributes)
: MvcHtmlString.Create("");
}
public static MvcHtmlString SecurityTrimmedActionLink(this HtmlHelper htmlHelper, string linkName, string actionName, string controllerName)
{
return htmlHelper.HasActionPermission(actionName, controllerName)
? htmlHelper.ActionLink(linkName, actionName, controllerName)
: MvcHtmlString.Create("");
}
public static MvcHtmlString SecurityTrimmedActionLink(this HtmlHelper htmlHelper, string linkName, string actionName, string controllerName, object routeValues, object htmlAttributes)
{
return htmlHelper.HasActionPermission(actionName, controllerName)
? htmlHelper.ActionLink(linkName, actionName, controllerName, routeValues, htmlAttributes)
: MvcHtmlString.Create("");
}
}
警告:这在MVC 5中不起作用,因为对FindAction()的调用从未返回操作描述符
我试图找到这个问题,但没能找到,最后我编了一个解决方案(面积部分比仅仅添加一些重载要复杂一些。 UseNamespaceFallback hack不起作用,因为当您在不同区域中拥有相同名称的控制器时,您将实例化错误的控制器 您需要有一种方法来获取该区域的正确名称空间 否则这个
IController controller = factory.CreateController(helper.ViewContext.RequestContext, controllerName);
会出问题的
目前我在视图中有这样的链接
@Html.SecurityTrimmedActionLink("this link", "Index", "Home",new {Area=string.Empty});
@Html.SecurityTrimmedActionLink("this link", "Index", "FunctionAdministration", new {Area="Administration" }, null);
里面
public static bool HasActionPermission(this HtmlHelper htmlHelper, string actionName, string controllerName, object area)
当区域为空时,我将获取该区域的名称空间或默认名称空间
private static string GetNamespaceForArea(string area, RouteCollection routeColl)
{
string ns = string.Empty;
foreach (RouteBase routeBase in routeColl)
{
if (routeBase.GetType() == (typeof (Route)))
{
Route route = (Route) routeBase;
RouteValueDictionary dataTokens = route.DataTokens;
;
if (area != null)
{
if (dataTokens.ContainsKey("area"))
{
if (area.Equals(dataTokens["area"]))
{
ns = (string) ((string[]) dataTokens["Namespaces"])[0];
break;
}
}
else
{
if (area.Equals(string.Empty))
{
ns = (string) ((string[]) dataTokens["Namespaces"])[0];
break;
}
}
}
}
}
return ns;
}
例如,您需要在GlobalAX中的路由中设置默认名称空间(默认ns“ActionLinkTest.Controllers”):
使用它根据类型名称创建控制器:
ControllerBase controllerToLinkTo = string.IsNullOrEmpty(controllerName) ? htmlHelper.ViewContext.Controller :(ControllerBase) Activator.CreateInstance(Type.GetType(type));
在global.asax中定义区域
areaRegistration.Add("Administration","Areas.Administration");
jfar的代码在很大程度上适用于我,但我不得不对MVC4进行一些修改。这是唯一需要更改的方法:
private static bool ActionIsAuthorized(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
{
if (actionDescriptor == null)
return false; // action does not exist so say yes - should we authorise this?!
AuthorizationContext authContext = new AuthorizationContext(controllerContext, actionDescriptor);
// run each auth filter until on fails
// performance could be improved by some caching
foreach (var filter in FilterProviders.Providers.GetFilters(controllerContext, actionDescriptor))
{
var authFilter = filter.Instance as IAuthorizationFilter;
if (authFilter == null)
continue;
authFilter.OnAuthorization(authContext);
if (authContext.Result != null)
return false;
}
return true;
}
在我的例子中,我希望我的逻辑留在控制器端。因此我删除了对
HtmlHelper
的依赖。这些更改很小,但可能会有所帮助
protected bool HasActionPermission(string actionName, string controllerName)
{
if (string.IsNullOrWhiteSpace(controllerName))
return false;
var controller = GetControllerByName(ControllerContext.RequestContext, controllerName);
var controllerDescriptor = new ReflectedControllerDescriptor(controller.GetType());
var actionDescriptor = controllerDescriptor.FindAction(ControllerContext, actionName);
return ActionIsAuthorized(ControllerContext, actionDescriptor);
}
private static bool ActionIsAuthorized(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
{
if (actionDescriptor == null)
return false; // action does not exist so say yes - should we authorise this?!
AuthorizationContext authContext = new AuthorizationContext(controllerContext, actionDescriptor);
// run each auth filter until on fails
// performance could be improved by some caching
foreach (var filter in FilterProviders.Providers.GetFilters(controllerContext, actionDescriptor))
{
var authFilter = filter.Instance as IAuthorizationFilter;
if (authFilter == null)
continue;
authFilter.OnAuthorization(authContext);
if (authContext.Result != null)
return false;
}
return true;
}
private static ControllerBase GetControllerByName(RequestContext context, string controllerName)
{
IControllerFactory factory = ControllerBuilder.Current.GetControllerFactory();
IController controller = factory.CreateController(context, controllerName);
if (controller == null)
{
throw new InvalidOperationException(
String.Format(
CultureInfo.CurrentUICulture,
"Controller factory {0} controller {1} returned null",
factory.GetType(),
controllerName));
}
return (ControllerBase)controller;
}
当您实现代码注释中提到的缓存时,是否可以更新此答案或发布新答案?:-)感谢堆。。。或者指向一个博客或资源,在那里可以随时更新。嘿,我正在努力让它工作,但在使用区域时似乎有问题。您以前在区域中使用过这个吗?为了修复此问题,我将UseNamespaceFallback的原始值存储在一个临时变量中,然后在CreateController之前将令牌设置为true。紧接着,我将其设置回原始值。当您使用Areas和MVC3时,方法private static ControllerBase GetControllerByName(HtmlHelper,string controllerName)似乎无法正常工作,特别是如果您有两个控制器使用相同的名称。当它们有相同名称的控制器时,使其与区域一起工作将非常好。我将@jfar的代码与MvcSiteMapProvider相结合,以提供对区域的支持。如果有人感兴趣,我已经把我在CodePlex上的东西放在了。源代码和二进制.NETFramework4.0DLL都在上面。
protected bool HasActionPermission(string actionName, string controllerName)
{
if (string.IsNullOrWhiteSpace(controllerName))
return false;
var controller = GetControllerByName(ControllerContext.RequestContext, controllerName);
var controllerDescriptor = new ReflectedControllerDescriptor(controller.GetType());
var actionDescriptor = controllerDescriptor.FindAction(ControllerContext, actionName);
return ActionIsAuthorized(ControllerContext, actionDescriptor);
}
private static bool ActionIsAuthorized(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
{
if (actionDescriptor == null)
return false; // action does not exist so say yes - should we authorise this?!
AuthorizationContext authContext = new AuthorizationContext(controllerContext, actionDescriptor);
// run each auth filter until on fails
// performance could be improved by some caching
foreach (var filter in FilterProviders.Providers.GetFilters(controllerContext, actionDescriptor))
{
var authFilter = filter.Instance as IAuthorizationFilter;
if (authFilter == null)
continue;
authFilter.OnAuthorization(authContext);
if (authContext.Result != null)
return false;
}
return true;
}
private static ControllerBase GetControllerByName(RequestContext context, string controllerName)
{
IControllerFactory factory = ControllerBuilder.Current.GetControllerFactory();
IController controller = factory.CreateController(context, controllerName);
if (controller == null)
{
throw new InvalidOperationException(
String.Format(
CultureInfo.CurrentUICulture,
"Controller factory {0} controller {1} returned null",
factory.GetType(),
controllerName));
}
return (ControllerBase)controller;
}