我正在开发一些网站,它是一种在线工作场所,会有一些用户和一些正在进行的计算机编程项目,每个用户可以有多个角色,例如一个特定用户可以是项目的项目经理和开发人员对于另一个项目。自然,项目经理在项目中比开发者拥有更多的权力。我的问题是如何在我的代码中巧妙地管理这个?我打算使用我的自定义角色提供程序并使用 Authorize 属性,但这还不够,因为我需要项目 ID 加上用户 ID 才能在特定项目中查找用户的角色。
7 回答
首先,您必须为您的扩展角色管理创建额外的表,例如projects
与users
上下文中的关系operations
,这可能是您的controller's actions
.
一种方法是为roles
. 在这种情况下,您将只使用 Asp net membership users
,但这完全取决于您的要求。
其次,您必须在 中处理它MVC
,在我看来,最好的方法是通过您自己的自定义Authorization
属性来实现它,并使用您的自定义授权属性而不是属性来装饰控制器的操作[Authorization]
。
它非常简单。
[CustomAuthorize]
//[Authorize]
public ActionResult GetProjectTasks(string projectname)
{
}
为此,您必须继承您的类,FilterAttribute
并且还必须实现IAuthorizationFilter
接口。
public void OnAuthorization(AuthorizationContext filterContext)
{
HttpCookie authCookie = filterContext.HttpContext.Request.Cookies[FormsAuthentication.FormsCookieName];
if (authCookie != null)
{
FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
var identity = new GenericIdentity(authTicket.Name, "Forms");
var principal = new GenericPrincipal(identity, new string[] { authTicket.UserData });
filterContext.HttpContext.User = principal;
}
var controller = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;
var action = filterContext.ActionDescriptor.ActionName;
var user = filterContext.HttpContext.User;
var ip = filterContext.HttpContext.Request.UserHostAddress;
var isAccessAllowed = CustomAuthenticationLogic.IsAccessAllowed(controller, action, user, ip);
if (!isAccessAllowed)
{
// Code if user is authenticated
FormsAuthentication.RedirectToLoginPage();
}
}
在该方法OnAuthorization
中,您可以获取自定义授权逻辑中可能需要的所有信息,例如HttpContext
姓名Controller
、Action
姓名。您只需从此方法调用您的自定义身份验证逻辑。您的自定义身份验证逻辑可能如下所示。
public class CustomAuthenticationLogic
{
public static bool IsAccessAllowed(string controller, string action, IPrincipal user, string ip)
{
//
// Your custom logic here
//
}
}
我不久前做了一些研究,可以向你保证:
- ASP.NET 内置功能很可能无济于事(没有办法考虑项目 ID 之类的东西)
- 基于角色的访问模型是最合适的,有不同的实现方式。Rusted 建议的 AzMan 实际上很好,但是管理上下文相关的规则可能会很困难。例如:用户 A 在项目 C 中执行操作 B,而它可以说是星期天。看看阿兹曼。
- 将您的访问规则与代码混合是非常糟糕的。您的安全模型不需要与它们的应用程序工作方式(ASP.NET MVC)相关,所以这个是错误的:
var isAllowed = AccessControl.IsAccessAllowed(controller, action, user, ip);
它必须看起来像:
var isAllowed = AccessControl.IsAccessAllowed(user, operation, context);
然后您可以随时使用它,在每个动作中或将其包装为属性。
其中操作是“登录”、“发布回复”、“阅读主题”等。上下文就是其他内容,例如“项目 id”、“星期几”、“用户 ip”等
可以写很多东西,比如角色重叠、上下文等。简而言之:谷歌的“.NET 基于角色的访问模型”可能更容易编写小型自定义安全框架。使其与用户、角色、操作和项目 ID 一起使用
操作被分配给角色,角色被分配给具有定义项目ID的用户,您可以对操作和角色进行硬编码,因此在您的数据库中只有一个小改动:用户到角色映射
如果您有更复杂的规则并且属性不够,那么您可以在控制器中计算用户是否可以访问某些功能并在您的 ViewModel 中添加反映访问或不访问这些功能的属性。
这样,您的视图将非常纤细,它会根据那些 ViewModel 布尔属性显示内容。
因此,假设您的用户只能阅读,您可以拥有一个属性 bool IsReadOnly,它将根据授权规则填充到控制器中,并且将在视图中用于例如生成标签而不是文本框。
我喜欢AzMan的主要思想是针对操作进行编程的概念。
操作是非常细化的东西,在使用上应该没有重叠,并且只能由开发人员定义。通过将操作分组到任务中,将任务分组到角色中,然后将主体(用户和组)映射到角色,您拥有一个非常强大的模型来在您的应用程序中定义授权。由于您直接对操作进行编程,因此您的代码不需要知道用户具有哪些角色,并且管理员可以在运行时更改这些角色。事实上,有人可以定义一组完全不同的角色来使用您在代码中使用的操作,而您根本不需要更改任何代码。这才是真正的力量所在。
我的意思不是“在您的应用程序中使用 AzMan”(但也许您应该尝试)。它是一个强大的模型,但它也很复杂,对于简单的事情来说可能是多余的。如果您只有一个或两个角色,并且他们保护的操作不重叠或不太可能改变,那么这可能是没有保证的。
我建议您Authorize
通过扩展内置AuthorizeAttribute
过滤器而不是实现IAuthorizationFilter
接口来创建自定义过滤器。内置的AuthorizeAttribute
做很多管道工作来处理缓存问题和其他事情,如果你要实现接口,你必须做所有这些工作。
您必须重写该AuthorizeCore
方法,并且您已经完成了所有角色检查逻辑。user id
你必须存储在会话中,你project id
必须弄清楚。
public override bool AuthorizeCore(HttpContextBase httpContext)
{
}
AuthorizeAttribute 源代码 - http://aspnetwebstack.codeplex.com/SourceControl/changeset/view/913d37658a44#src%2fSystem.Web.Mvc%2fAuthorizeAttribute.cs
自定义授权属性示例: http: //msdn.microsoft.com/en-us/library/ee707357 (v=vs.91).aspx
你可以有groups
基于roles
.
然后将不同的用户添加到特定的组。组可以 >
1) Admin Group
2) Developer Group
3) Project1-QA Group
4) Project2-Manager Group
保存 和 的映射[user - group]
,[group - projects]
具体取决于您的数据库设计。
您可以根据需要为一个用户拥有任意数量的角色(组)。
一种非常简单的方法 - 对于站点范围的访问控制,您可以将一个 INT 列添加到用户表并将该 INT 的每一位映射到一个[flags]
Enum - 例如[Flags] enum Access { UpdateProjects, AddProjects }
。
对于每个项目的访问控制,创建一个名为例如 ProjectAccessControl 的表,其中包含三列:ProjectID(Project 表的外键)、UserID(User 表的外键)和 Role (INT)。Role 列是一个 INT,它的每个位都应该表示不同的布尔标志(如前面的示例,您可以将其映射到 C# 中的枚举)并说如果第一个位打开,则用户有权更新描述,如果第二位打开,用户可以更改时间表等。
[Flags]
enum ProjectAccessRole
{
UpdateDescription,
ChangeSchedule,
etc...
}
在代码中,您可以测试用户的角色是否有权以这种方式更新计划:
if( (intUserRole & ProjectAccessRole.ChangeSchedule)
== ProjectAccessRole.ChangeSchedule)
{
/*user has right*/
}
然后您可以将此检查包装到一个简单的函数中,该函数采用两个参数,1) 如果角色具有 2) 角色,则要检查该角色。然后你只需调用HasRights(intUserRole, ProjectAccessRole.ChangeSchedule);
.