如何创建“安全感知”操作链接,以检测用户是否有权单击(调用)该操作?
如果不允许用户使用该操作,请隐藏链接.
依赖于
上的属性
PS
我想在MVC中混合这2是不好的做法吧?
发布于 2010-04-27 14:26:20
这是从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()的调用永远不会返回操作描述符
我试图找出这个问题,但没能解决,最后我做了一件工作。:(
发布于 2012-12-26 20:14:14
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;
}发布于 2012-03-22 09:07:10
区域部分比仅仅添加一些过载要复杂一些。UseNamespaceFallback黑客不起作用,因为当您在不同区域具有相同名称的控制器时,您将实例化错误。
您需要有一种方法为该区域获取正确的命名空间。
否则这个
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)当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;
}您需要在您的路由中以globalasax设置默认名称空间,例如如下(默认ns "ActionLinkTest.Controllers"):
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
, new[] { "ActionLinkTest.Controllers" }
);使用它创建基于类型名称的控制器:
ControllerBase controllerToLinkTo = string.IsNullOrEmpty(controllerName) ? htmlHelper.ViewContext.Controller :(ControllerBase) Activator.CreateInstance(Type.GetType(type));在global.asax中定义区域
areaRegistration.Add("Administration","Areas.Administration");https://stackoverflow.com/questions/2721869
复制相似问题