ASP.NET MVC中的非字符串角色名称?

Mik*_*att 26 asp.net-mvc roles

ASP.NET MVC对基于角色的安全性有很好的支持,但是将字符串用作角色名称是令人抓狂的,因为它们不能作为枚举强类型化.

例如,我的应用中有"管理员"角色."Admin"字符串现在将存在于我的操作的Authorize属性中,我的母版页(用于隐藏选项卡),我的数据库中(用于定义每个用户可用的角色)以及我的代码或视图中的任何其他位置我需要为管理员或非管理员用户执行特殊逻辑的文件.

是否有更好的解决方案,缺少编写我自己的授权属性和过滤器,这可能会处理枚举值的集合?

Joh*_*ika 49

使用魔术字符串可以灵活地在Authorize属性中声明多个角色(例如[Authorize(Roles ="Admin,Moderator")],当您转到强类型解决方案时,这些角色往往会丢失.但是这里是如何维护这个灵活性,同时仍然可以输入所有内容.

在使用位标志的枚举中定义您的角色:

[Flags]
public enum AppRole {
    Admin = 1,
    Moderator = 2,
    Editor = 4,
    Contributor = 8,
    User = 16
}
Run Code Online (Sandbox Code Playgroud)

覆盖AuthorizeAttribute:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class MyAuthorizeAttribute : AuthorizeAttribute {

    public AppRole AppRole { get; set; }

    public override void OnAuthorization(AuthorizationContext filterContext) {
        if (AppRole != 0)
            Roles = AppRole.ToString();

        base.OnAuthorization(filterContext);
    }

}
Run Code Online (Sandbox Code Playgroud)

现在,如果您可以像这样使用MyAuthorizeAttribute:

[MyAuthorize(AppRole = AppRole.Admin | AppRole.Moderator | AppRole.Editor)]
public ActionResult Index() {

    return View();
}
Run Code Online (Sandbox Code Playgroud)

以上操作仅授权至少列出其中一个角色的用户(管理员,主持人或编辑者).该行为与MVC的默认AuthorizeAttribute相同,除了没有魔术字符串.

如果您使用此技术,这里是IPrincipal上的扩展方法,也可能有用:

public static class PrincipalExtensions {

    public static bool IsInRole(this IPrincipal user, AppRole appRole) {

        var roles = appRole.ToString().Split(',').Select(x => x.Trim());
        foreach (var role in roles) {
            if (user.IsInRole(role))
                return true;
        }

        return false;
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以像这样使用此扩展方法:

public ActionResult Index() {
    var allowed = User.IsInRole(AppRole.Admin | AppRole.Moderator | AppRole.Editor);

    if (!allowed) {
       // Do Something
    }

    return View();
}
Run Code Online (Sandbox Code Playgroud)


Mat*_*nen 21

我通常使用一个带有一串字符串常量的类.这不是一个完美的解决方案,因为你需要记住在任何地方坚持使用它,但至少它摆脱了拼写错误的可能性.

static class Role {
    public const string Admin = "Admin";
}
Run Code Online (Sandbox Code Playgroud)


Jon*_*noW 10

虽然它不使用枚举,但我使用了下面的解决方案,我们在其中对Authorize过滤器进行子类化,以在构造函数中接受可变长度角色名称参数.将它与const变量中声明的角色名一起使用,我们避免使用魔术字符串:

public class AuthorizeRolesAttribute : AuthorizeAttribute
{
    public AuthorizeRolesAttribute(params string[] roles) : base()
    {
        Roles = string.Join(",", roles);
    }
}

public class MyController : Controller
{
    private const string AdministratorRole = "Administrator";
    private const string AssistantRole = "Assistant";

    [AuthorizeRoles(AdministratorRole, AssistantRole)]
    public ActionResult AdminOrAssistant()
    {                        
        return View();
    }
}
Run Code Online (Sandbox Code Playgroud)

(我在稍微详细的博客中写了这篇文章 - http://tech-journals.com/jonow/2011/05/19/avoiding-magic-strings-in-asp-net-mvc-authorize-filters)