c# - 如何在 ASP.NET MVC 4 中获取 Controller 操作的自定义注释属性?

标签 c# asp.net-mvc razor

我在 ASP.NET MVC 中为我的应用程序使用基于权限的授权系统。 为此,我创建了一个自定义授权属性

public class MyAuthorizationAttribute : AuthorizeAttribute
{
    string Roles {get; set;}
    string Permission {get; set;}
}

这样我就可以通过角色或带有注释的特定权限 key 来授权用户,例如

public class UserController : Controller
{
    [MyAuthorization(Roles="ADMIN", Permissions="USER_ADD")]
    public ActionResult Add()

    [MyAuthorization(Roles="ADMIN", Permissions="USER_EDIT")]
    public ActionResult Edit()

    [MyAuthorization(Roles="ADMIN", Permissions="USER_DELETE")]
    public ActionResult Delete()
}

然后我用类似的逻辑(伪代码)覆盖 MyAuthorizationAttribute 类中的 AuthorizeCore() 方法

protected override bool AuthorizeCore(HttpContextBase httpContext)
{
    if(user not authenticated)
        return false;

    if(user has any role of Roles)
        return true;

    if(user has any permission of Permissions)
        return true;

    return false;
}

到目前为止一切正常。

现在我需要某种扩展方法,以便我可以在 View 页面中动态生成操作 url,该 url 将根据给定操作的 MyAuthorization 属性授权逻辑返回操作 url。喜欢

@Url.MyAuthorizedAction("Add", "User")

如果用户具有管理员角色或具有“USER_ADD”权限(在操作的属性中定义),则返回“用户/添加”的 url,否则返回空字符串。

但是在网上查了几天,还是没弄明白。 :(

到目前为止我只找到了这个 "Security aware" action link?它通过执行操作的所有操作过滤器来工作,直到它失败。

这很好,但我认为每次调用 MyAuthorizedAction() 方法时执行所有操作筛选器会产生开销。此外它也不适用于我的版本(MVC 4 和 .NET 4.5)

我需要做的就是根据给定操作的授权角色和权限检查经过身份验证的用户的角色、权限(将存储在 session 中)。像下面的东西(伪代码)

MyAuthorizedAction(string actionName, string controllerName)
{
    ActionObject action = SomeUnknownClass.getAction(actionName, controllerName)
    MyAuthorizationAttribute attr = action.returnsAnnationAttributes()

    if(user roles contains any in attr.Roles 
       or 
       user permissions contains any attr.Permissions)
    {
        return url to action
    }
    return empty string
}

我找了很久的获取 Action 属性值的解决方案,一直找不到足够好的资源。我错过了正确的关键字吗? :/

如果有人能为我提供真正有帮助的解决方案。 提前感谢解决方案

最佳答案

虽然我同意基于权限生成 url 可能不是最佳实践,但如果您仍然想继续,您可以使用这些找到操作及其属性:

检索“操作”方法: 这将检索方法信息的集合,因为可能有多个 Controller 类具有相同的名称和多个具有相同名称的方法,特别是在使用区域时。如果你不得不担心这个,我会把歧义留给你。

public static IEnumerable<MethodInfo> GetActions(string controller, string action)
{
    return Assembly.GetExecutingAssembly().GetTypes()
           .Where(t =>(t.Name == controller && typeof(Controller).IsAssignableFrom(t)))
           .SelectMany(
                type =>
                type.GetMethods(BindingFlags.Public | BindingFlags.Instance)
                    .Where(a => a.Name == action && a.ReturnType == typeof(ActionResult))
             );

}

从 MyAuthorizationAttributes 中检索权限:

public static MyAuthorizations GetMyAuthorizations(IEnumerable<MethodInfo> actions)
{
    var myAuthorization = new MyAuthorizations();
    foreach (var methodInfo in actions)
    {
        var authorizationAttributes =  methodInfo
                .GetCustomAttributes(typeof (MyAuthorizationAttribute), false)
                .Cast<MyAuthorizationAttribute>();
        foreach (var myAuthorizationAttribute in authorizationAttributes)
        {
            myAuthorization.Roles.Add(MyAuthorizationAttribute.Role);
            myAuthorization.Permissions.Add(MyAuthorizationAttribute.Permission);
        }
    }
    return myAuthorization;
}
public class MyAuthorizations
{
    public MyAuthorizations()
    {
        Roles = new List<string>();
        Permissions = new List<string>();
    }
    public List<string> Roles { get; set; }
    public List<string> Permissions { get; set; }
}

最后是 AuthorizedAction 扩展: 警告:如果给定的 Controller /操作对有多个匹配项,如果用户获得其中任何一个的授权,这将提供“授权”url。 ..

public static string AuthorizedAction(this UrlHelper url, string controller, string action)
{
    var actions = GetActions(controller, action);
    var authorized = GetMyAuthorizations(actions);
    if(user.Roles.Any(userrole => authorized.Roles.Any(role => role == userrole)) ||
       user.Permissions.Any(userPermission => authorized.Permissions.Any(permission => permission == userPermission)))
    {
        return url.Action(controller,action)
    }
    return string.empty;
}

根据权限生成url的注意事项:
我声明这可能不是最佳实践,因为有很多小问题。根据您的情况,每个人都可能有自己的相关程度。

  • 给人的印象是试图通过默默无闻来实现安全。 如果我不给他们看 url,他们就不会知道它在那里。
  • 如果您已经在以其他方式检查权限以控制页面的呈现(看起来您正在根据您在其他地方的评论所做的事情),那么明确不写出 url 是没有意义的。 最好不要调用 Url.Action 方法。
  • 如果您还没有根据用户的权限控制页面的呈现,那么简单地为 url 返回空字符串将会在您的页面上留下很多损坏的或看似损坏的内容。 嘿,当我按下这个按钮时,它没有任何反应!
  • 这会使测试和调试变得更加复杂:是因为权限不正确导致 url 不显示,还是存在其他错误?
  • AuthorizedAction 方法的行为似乎不一致。有时返回一个 url,有时返回一个空字符串。

通过操作授权属性控制页面呈现:AuthorizedAction 方法修改为 boolean,然后使用其结果来控制页面呈现。

public static bool AuthorizedAction(this HtmlHelper helper, string controller, string action)
{
    var actions = GetActions(controller, action);
    var authorized = GetMyAuthorizations(actions);
    return user.Roles.Any(userrole => authorized.Roles.Any(role => role == userrole)) ||
       user.Permissions.Any(userPermission => authorized.Permissions.Any(permission => permission == userPermission))
}

然后在您的 Razor 页面中使用它。

@if(Html.AuthorizedAction("User","Add")){
   <div id='add-user-section'>
        If you see this, you have permission to add a user.
        <form id='add-user-form' submit='@Url.Action("User","Add")'>
             etc
        </form>
   </div>
}
else {
  <some other content/>

}

关于c# - 如何在 ASP.NET MVC 4 中获取 Controller 操作的自定义注释属性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13201250/

相关文章:

c# - DbSet<T>.Where(where).ToList() - 为什么 SQL 不包含 where 子句?

c# - LINQ Where(Array.Contains) 中的速度改进

.net - 如何在 ViewBag 中传递变量列表

c# - MVC.net 应用程序中的不同日期和日期时间

javascript - 无法附加带有静态选项的下拉列表

c# - View 名称参数错误的 DisplayForModel

c# - 在C#中为字符串分配双引号的最易读的方法

c# - WPF、MVVM 和 PRISM - 没有为此对象定义无参数构造函数

c# - Asp.Net MVC 与 Java MVC 框架相比如何

javascript - Asp mvc razor 在文本框中存储输入文件的值