我与我的ASP.NET MVC应用程序基于权限的授权系统的工作。 为此,我创建了一个自定义的授权属性
public class MyAuthorizationAttribute : AuthorizeAttribute
{
string Roles {get; set;}
string Permission {get; set;}
}
这样我可以授权由两个角色或标注特定权限密钥像操作的用户
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()
}
然后我重写AuthorizeCore()方法在MyAuthorizationAttribute类具有相似逻辑(伪码)
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;
}
截至本是工作的罚款。
现在我需要某种形式的扩展方法,这样我可以动态地查看页面,将基于对给定的动作MyAuthorization属性授权逻辑回归动作URL生成操作URL。 喜欢
@Url.MyAuthorizedAction("Add", "User")
将返回URL“用户/添加”,如果用户具有管理员角色或拥有“USER_ADD”的权限(如在动作属性定义)或否则返回空字符串。
但在互联网的几天里进行搜索后我无法弄清楚。 :(
到目前为止,我只发现了这个“安全意识”操作链接? 其通过执行所有操作筛选的动作,直到它失败的作品。
这是不错的,但我认为这将是执行所有操作器中的每我所说的MyAuthorizedAction()方法的时间开销。 另外它也没有用我的版本(MVC 4和.NET 4.5)工作
什么我需要的是检查身份验证的用户的角色,权限(将存储在会议)在针对给定的操作授权的角色和权限。 喜欢的东西如下(伪代码)
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属性值,都无法找到足够好的资源的解决方案。 我缺少了正确的关键字? :/
如果任何人都可以向我提供的解决方案,这将是真正有很大的帮助。 预先感谢解决方案
Answer 1:
虽然我同意,根据权限生成的URL可能不是最好的做法,如果你想继续反正你可以找到的行动,并使用这些它们的属性:
检索“操作”方法:这种方法获取的相关信息的集合,因为它可能有多个控制器类具有相同的名称,尤其是名称相同的多个方法与使用领域。 如果你担心这个,我会离开歧给你。
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扩展:警告:如果你有一个给定控制器/动作对这样会给“授权”的网址,如果用户将有权使用其中的任何一个以上的比赛...
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.Action方法。
- 如果不根据用户的权限已经控制了页面的渲染,简单地返回对于网址空字符串会留下很多的断裂或破碎看似内容在您的网页。 嘿,当我按下这个按钮不会做任何事情!
- 它可以使测试和调试更加复杂: 是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))
}
然后,在你的剃须刀的网页使用。
@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/>
}
Answer 2:
我不认为你应该检查行动注解要创建Url.Action)的URL(各一次。 如果动作被固定与自定义授权过滤器不会对非特权用户执行,因此,什么是在隐藏URL到行动的地步? 相反,你可以在实施的HtmlHelper扩展方法来检查当前用户是否具有给定的premission,如:
public static bool HasPermission(this HtmlHelper helper, params Permission[] perms)
{
if (current user session has any permission from perms collection)
{
return true;
}
else
{
return false;
}
}
然后,你可以使用助手的意见,里面隐藏不适用于当前用户,就像访问按钮和链接:
@if (Html.HasPermission(Permission.CreateItem))
{
<a href="@Url.Action("Items", "Create")">Create item</a>
}
当然,这隐藏特定的链接仅用于UI目的 - 获得真正的控制研究是由自定义授权属性来完成。
Answer 3:
我唯一的建议是写一个扩展方法IPrincipal
代替它会是什么样子
public static bool HasRolesAndPermissions(this IPrincipal instance,
string roles,
string permissions,)
{
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;
}
然后你的意见/泛音代码是有点更具可读性在它实际上做什么(不这样做的HTML什么,但验证用户),然后在视图/谐音代码如下条款
@if (User.HasRolesAndPermissions(roles, permissions))
{
@Html.ActionLink(..);
}
每一个MVC页面具有以下属性: WebViewPage.User当前用户。
与你的解决方案望目(和链接安全感知链路)的问题是,链接,并在控制器授权的创建可以是不同的(并且在我看来,这类型的时尚混合职责是不好的做法)。 通过扩展IPrincipal
新的授权将如下所示:
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
return user.HasRolesAndPermissions(roles, permissions)
}
现在无论你的授权属性和视图使用相同的角色/权限数据逻辑。
文章来源: How to get custom annotation attributes for a controller action in ASP.NET MVC 4?