与MVC的网站有一定的要求细化的权限 [英] Granular permissions with certain requirements for an MVC site
问题描述
我不喜欢内置的会员供应商。我决定推出自己的。我想拿出的行动水平执行授权的好方法。下面是我的试图要求的由去:
I don't like the built in membership providers. I've decided to roll my own. I'm trying to come up with a good method for performing authorization at the action level. Here are the requirements that I'm trying to go by:
- 属性的用法 - 我喜欢这个,因为它在调用堆栈一个相当高的水平控制,是一个不错的地方,组织权限
- 无幻字符串 - 这就是为什么我偏离从目前的角色提供远的原因。我不想离开琴弦躺在身边,不能轻易改名。
- 权限应可组成的有一个的其他权限。例如:
读写
有读
许可。就像有一个枚举OR符号。
- Attribute usage - I like this since it controls at a very high level in the call stack and is a nice place to organize permissions.
- No magic strings - This is a reason why I'm straying away from the current role providers. I don't want to leave strings lying around that can't be easily renamed.
- Permissions should can be composed of one other permission. Example:
ReadWrite
has permission forRead
. Just like or'ing with an enum.
请注意:有些人认为这组要求过于宽泛(见注释)。我不这么认为,我认为他们是非常简单的。
NOTE: Some think this set of requirements is too broad (see comments). I don't think so, I think they're fairly straightforward.
最大的搅局者是属性的使用。只能有恒恩pressions的typeof前pressions或属性参数类型的数组创建前pression。
The biggest showstopper is attribute usage. There can only be "constant expressions, typeof expressions or array creation expression of an attribute parameter type".
我在想也许有这样的事情,使操作具有静态访问。里面的属性,这将转换的INT实际权限或东西...:
I was thinking of perhaps having something like this to make operations have static access. Inside of the attribute, it would "convert" the int to the actual Permission or something...:
public static class Operations
{
public static class SectionA
{
public const int Read = 1;
public const int ReadWrite = 2;
}
public static class SectionB
{
// ... and so on...
}
}
但它确实限制组成。我敢肯定,你在想你为什么不走枚举路线?好,我想计划要改变环境,不希望限制到32(INT)或64(长)操作,并有后来做了大规模的改写(也在这只是丑陋的DB)。
But it really limits composition. I'm sure you're thinking "why don't you go the enum route?" well I want to plan for things to change and don't want to limit to 32 (int) or 64 (long) operations and have to do a massive rewrite later (also in the db that's just ugly).
此外,如果有比动作/控制器属性更好的选择,那么我所有的耳朵建议。
Also, if there is a better alternative than attributes on actions/controllers, then I'm all ears for suggestions.
编辑:另外从<一个href=\"http://stackoverflow.com/questions/1060760/what-to-do-when-bit-mask-flags-enum-gets-too-large\">this帖子,我读过有关 BitArray
类。看来的样的的丑陋,尤其是在数据库中存储的任意
Also from this post, I've read about the BitArray
class. It seems kind of ugly, especially with the arbitrary storage in the database.
推荐答案
首先,我要感谢你拉我进回答这个问题;)
First of all, I have to thank you for sucking me into answering this ;)
这是一个长期的答案,只是一个起点。你必须弄清楚如何将角色分配给用户,以及如何重新创建它们在的AuthenticateRequest
。
This is a long answer, and is only a starting point. You have to figure out how to assign roles to users and how to recreate them in the AuthenticateRequest
.
如果这不回答你的问题,我希望这将是一种鼓舞。尽情享受吧!
If this does not answer your question, I hope it will be an inspiration. Enjoy!
装饰控制器动作
我开始装点在默认的两个动作的HomeController
:
I started to decorate the two actions in the default HomeController
:
[AuthorizeRoles(Role.Read)]
public ActionResult Index()
{
ViewData["Message"] = "Welcome to ASP.NET MVC!";
return View();
}
[AuthorizeRoles(Role.Write)]
public ActionResult About()
{
return View();
}
在读写角色的所有用户应该再被授予访问权限。我选择在这里使用一个枚举作为魔术字符串类型安全的占位符。此枚举的作用无非是一个占位符别人。没有复合枚举值,即必须保持在其他地方。后来更多。
All users in the ReadWrite role should then be granted access. I opted here to use an enum as a type safe placeholder for the magic strings. The role of this enum is nothing else than being a placeholder. There are no composite enum values, that has to be maintained somewhere else. More on that later.
public enum Role
{
Read,
Write,
ReadWrite
}
实现新的授权属性
由于琴弦都走了,我需要一个新的授权属性:
Since the strings are gone, I need a new authorize attribute:
public class AuthorizeRolesAttribute : AuthorizeAttribute
{
private readonly RoleSet authorizedRoles;
public AuthorizeRolesAttribute(params Role[] roles)
{
authorizedRoles = new RoleSet(roles);
}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
return authorizedRoles.Includes(httpContext.User);
}
}
的 RoleSet
包装一组枚举值,并验证如果的IPrincipal
就是其中之一的成员:
The RoleSet
wraps a set of enum values and verifies if an IPrincipal
is a member of one of them:
public class RoleSet
{
public RoleSet(IEnumerable<Role> roles)
{
Names = roles.Select(role => role.ToString());
}
public bool Includes(IPrincipal user)
{
return Names.Any(user.IsInRole);
}
public bool Includes(string role)
{
return Names.Contains(role);
}
public IEnumerable<string> Names { get; private set; }
}
维护角色
的 CompositeRoleSet
是复合角色注册并处理。 CreateDefault()
是所有复合材料登记。解析()
将角色(枚举值)的列表和复合材料转换成他们唯一的同行。
The CompositeRoleSet
is where composite roles are registered and handled. CreateDefault()
is where all composites are registered.
Resolve()
will take a list of roles (enum values) and convert the composites to their single counterparts.
public class CompositeRoleSet
{
public static CompositeRoleSet CreateDefault()
{
var set = new CompositeRoleSet();
set.Register(Role.ReadWrite, Role.Read, Role.Write);
return set;
}
private readonly Dictionary<Role, Role[]> compositeRoles = new Dictionary<Role, Role[]>();
private void Register(Role composite, params Role[] contains)
{
compositeRoles.Add(composite, contains);
}
public RoleSet Resolve(params Role[] roles)
{
return new RoleSet(roles.SelectMany(Resolve));
}
private IEnumerable<Role> Resolve(Role role)
{
Role[] roles;
if (compositeRoles.TryGetValue(role, out roles) == false)
{
roles = new[] {role};
}
return roles;
}
}
接线起来
我们需要一个身份验证的用户去努力。我欺骗和硬codeD之一的Global.asax:
We need an authenticated user to work on. I cheated and hard-coded one in global.asax:
public MvcApplication()
{
AuthenticateRequest += OnAuthenticateRequest;
}
private void OnAuthenticateRequest(object sender, EventArgs eventArgs)
{
var allRoles = CompositeRoleSet.CreateDefault();
var roles = allRoles.Resolve(Role.ReadWrite);
Context.User = new ApplicationUser(roles);
}
最后,我们需要一个的IPrincipal
这明白这一切:
public class ApplicationUser : IPrincipal
{
private readonly RoleSet roles;
public ApplicationUser(RoleSet roles)
{
this.roles = roles;
}
public bool IsInRole(string role)
{
return roles.Includes(role);
}
public IIdentity Identity
{
get { return new GenericIdentity("User"); }
}
}
这篇关于与MVC的网站有一定的要求细化的权限的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!