C# ASP.NETMVC5:为基于web的产品设计基于角色的访问系统的最佳方法
我可能不得不开发一个ERP系统,它不是面向公众的网站,而是由特定组织的不同用户使用。我正在寻找一个最好的想法,以设计用户权限系统领域的管理员分配访问权的角色,并分配给用户的角色。角色明智的用户可以或不能访问网页 最初我有一些想法,我想简单地讨论一下。告诉我我的方向对吗 假设我的网站将有人力资源相关页面、销售和账户相关页面。因此,任何用户都不能访问HR或帐户、采购相关页面。管理员授予用户访问该区域的权限的方式 假设在第一页中,管理员将在主表中保存所有控制器名称及其操作名称 对于管理员页面,我将显示所有控制器和操作名称以及隐藏的id 比如说人力资源总监 等 因此,管理员首先创建几个角色,如人力资源、帐户、采购和销售等 管理员首先从下拉列表中选择角色 下面我将显示控制器操作名称。管理员只需勾选控制器名称和几个动作名称,并保存在数据库中的信息。我将在其中保存角色id和控制器id、操作id 通过这种方式,我可以将控制器和操作id附加到角色。当分配此角色时,将使用角色id和用户id保存在数据库中 在控制器级别或操作级别,我将编写一个自定义属性,通过该属性我将验证特定用户是否具有访问此操作的角色和权限 因为我不想用这种方式硬编码角色C# ASP.NETMVC5:为基于web的产品设计基于角色的访问系统的最佳方法,c#,asp.net-mvc,C#,Asp.net Mvc,我可能不得不开发一个ERP系统,它不是面向公众的网站,而是由特定组织的不同用户使用。我正在寻找一个最好的想法,以设计用户权限系统领域的管理员分配访问权的角色,并分配给用户的角色。角色明智的用户可以或不能访问网页 最初我有一些想法,我想简单地讨论一下。告诉我我的方向对吗 假设我的网站将有人力资源相关页面、销售和账户相关页面。因此,任何用户都不能访问HR或帐户、采购相关页面。管理员授予用户访问该区域的权限的方式 假设在第一页中,管理员将在主表中保存所有控制器名称及其操作名称 对于管理员页面,我将显示
[Authorize(Roles = "Producer")]
[Authorize(Roles = "Admin")]
public ActionResult Details(int id) {
// Only available to users who are Producers AND Editors
}
我更愿意按照下面的方式来做
public class DynamicRoleAuthorizeAttribute: AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var controller = httpContext.Request.RequestContext
.RouteData.GetRequiredString("controller");
var action = httpContext.Request.RequestContext
.RouteData.GetRequiredString("action");
// feed the roles here
Roles = string.Join("," ,_rolesProvider.Get(controller, action));
return base.AuthorizeCore(httpContext);
}
}
[DynamicRoleAuthorize]
public ActionResult MyAction()
{
}
但我的问题是,如果任何开发人员错误地更改了cs文件中的任何操作或控制器名称,那么我如何管理整个过程。错误地,如果任何控制器名称或操作名称发生更改,那么我的想法将无法正常工作
因此,请指导我如何在asp.net mvc 5中设计这种权限系统,它将不依赖于控制器名称或操作名称。如果这些名称发生更改,那么权限也应该起作用
请用idea或一些代码示例指导我在基于web的产品中实现。或者告诉我其他有经验的开发人员,他们是如何处理这种情况的。寻找实施这种许可制度的最佳指南
我搜索了谷歌,但没有找到我可以遵循的好的解决方案。有很多关于asp.NETMVC的文章,但这是任何产品中非常重要的一部分,根据我对谷歌搜索的了解,它并没有涉及太多内容
如果有人获得与此主题相关的任何文章链接,请与我共享RBAC系统的url。若这篇文章是关于asp.net核心mvc的,那个么这也将帮助我了解这个想法
谢谢我的第一个倾向是投票结束这个问题,因为它正在寻求意见;几乎是一篇描述如何设计灵活许可系统的博客文章。网上有很多,包括我链接到的微软文档。所以,如果你在谷歌上找不到任何东西,那么你正在努力寻找你想要的东西 基本上,权限系统涉及参与者(通常是用户)和安全资源(例如API)。挑战在于能够为用户分配权限,并在用户调用API时验证这些权限。API所需的权限可以且应该硬编码:
[FuncPermission("GetHrData")]
public ActionResult Details(int id) {
// Only available to users that have GetHrData Permission
}
然后定义角色(用户组),并为角色分配权限。在我看来,您不应该硬编码Authorize
属性中的角色
你将从这里走向何方
坦白说,还有很多其他的事情你也需要考虑。开发ERP相当复杂(即使您不打算与市场上众多优秀的ERP系统竞争)。如果你是第一次实施授权,我建议雇佣一个能帮助你并培训你的人。可能不便宜-但肯定比最终得到需要废弃和重写的系统便宜我回顾了一个旧的MVC 5项目,发现这是一个起点 我假设每个控制器都有读/写/编辑/删除或基本CRUD操作。我创建了一些代码,使用反射来查看项目,对于每个控制器,生成了四个声明-控制器名称和四个可能操作中的每一个。我手动创建了菜单选项的声明。这样,视图可以隐藏或禁用不允许用户访问的菜单选项 这是一个典型的控制器动作。在我的例子中,一个用户想要取消一张发票,这将是成功还是失败——所有的工作都在一个业务模型中执行,以保持控制器操作的轻量级。无论视图是否授予用户取消发票的权限,执行操作的安全带和支架都是有效的
[FuncPermission("GetHrData")]
public ActionResult Details(int id) {
// Only available to users that have GetHrData Permission
}
[ClaimsAuthorize("InvoicesController", "Edit")]
[ValidateAntiForgeryToken]
[HttpPost]
public async Task<ActionResult> CancelInvoice(InvoiceView v)
{
var user = _userManager.FindById(User.Identity.GetUserId());
await _bs.CancelInvoice_Async(v, ModelState, user.Id);
if (ModelState.IsValid)
{
// state saved
return RedirectToAction("Edit", new { id = v.InvoiceId });
}
// not saved
return View("Edit", v);
}
/// <summary>
/// Allows use of an authorisation attribute on controllers and controller methods
/// </summary>
public class ClaimsAuthorizeAttribute : AuthorizeAttribute
{
private string claimType;
private string claimValue;
/// <summary>
/// Authorise using a claim by type (and optional value)
/// </summary>
/// <param name="type">The Claim Type - Usually [Controller]_[Action]</param>
/// <param name="value">The Claim Value, usually one of Read | Edit | Create | Delete, or some other relevant value</param>
public ClaimsAuthorizeAttribute(string type, string value = "")
{
this.ClaimType = type;
this.ClaimValue = value;
}
/// <summary>
/// Gets the Claim Type - Usually [Controller]_[Action]
/// </summary>
public string ClaimType { get => claimType; protected set => claimType = value; }
/// <summary>
/// Gets the Claim Value, usually one of Read | Edit | Create | Delete, or some other relevant value
/// </summary>
public string ClaimValue { get => claimValue; protected set => claimValue = value; }
public override void OnAuthorization(AuthorizationContext filterContext)
{
// assume not authorised
bool isAuthorised = false;
// check user exists
if (filterContext.HttpContext.User != null)
{
// get user by claim principle
var user = filterContext.HttpContext.User as System.Security.Claims.ClaimsPrincipal;
if (user != null && user.HasClaim(ClaimType, ClaimValue))
{
// user has a claim of the correct type
isAuthorised = true;
}
}
if (isAuthorised)
{
filterContext.Result = null;
base.OnAuthorization(filterContext);
}
else
{
// we don't use 401 as this will cause a login loop : base.HandleUnauthorizedRequest(filterContext);
// Forbidden message will be shown
filterContext.Result = new HttpStatusCodeResult(HttpStatusCode.Forbidden, "You are forbidden to access this resource");
}
}
}