如何为特许经营企业进行基于角色的访问控制?

发布于 2024-08-30 11:44:27 字数 2321 浏览 4 评论 0原文

我正在 ASP.NET MVC 2 中为特许经营服务业务构建基于 Web 的 CRM+CMS 的第二次迭代。我需要根据为该特许经营的用户分配的角色来控制对每个特许经营的服务的访问。

4 个示例:

  • 接待员 应该能够为她的“Atlantic Seaboard”特许经营权预订服务工作,但不能做任何报告。
  • 技术人员应该能够改变服务工作,但不能修改发票。
  • 经理应该能够对其商店内的工作发票应用折扣。
  • 所有者应该能够提取他拥有的任何特许经营权的报告。

特许经营级访问控制应位于数据 - 服务 - Web 层之间的什么位置?
如果它属于我的控制器,我应该如何最好地实现它?

部分架构

Roles

int ID { get; set; } // primary key for Role
string Name { get; set; }

部分 Franchises

short ID { get; set; } // primary key for Franchise
string Slug { get; set; } // unique key for URL access, eg /{franchise}/{job}
string Name { get; set; }

UserRoles 使用 [Authorize] 属性映射

short FranchiseID; // related to franchises table
Guid UserID; // related to Users table
int RoleID; // related to Roles table
DateTime ValidFrom;
DateTime ValidUntil;

控制器实现

访问控制

如果只有涉及一个特许经营权,我可以简单地限制对控制器操作的访问,如下所示:

[Authorize(Roles="Receptionist, Technician, Manager, Owner")]
public ActionResult CreateJob(Job job)
{
    ...
}

由于特许经营权不会在一夜之间突然出现,也许这是使用 ASP 中新的区域功能的有力案例。 NET MVC 2?或者这会导致重复的视图吗?

控制器、URL 路由和区域

假设未使用区域,那么确定正在访问哪个特许经营权的数据的最佳方法是什么?我想到了这一点:

{franchise}/{controller}/{action}/{id}

或者更好的是在“详细信息(...)”操作中确定一份工作的特许经营权并使用[授权]限制用户的操作:

{job}/{id}/{action}/{subaction}
{invoice}/{id}/{action}/{subaction}

如果任何用户可以在没有授权的情况下访问多个特许经营权,那么这更有意义。使用 {franchise} 参数使 URL 变得混乱。

任何意见都会受到赞赏。

编辑:

背景

我用经典 ASP 构建了以前的 CRM,业务运行良好,但现在是升级的时候了,以加快工作流程并减少出错的空间。为了正确测试以及更好地分离数据和表示,我决定实现存储库模式,如 Rob Conery 的 MVC Storefront 系列中所示。

如何安排服务和存储库?

拥有一个基于可用过滤器检索任何服务作业的 JobService 是有意义的,例如。 IQueryable<作业>; GetJobs();。但由于一项工作只能属于一个特许经营权,因此像 IQueryable这样的函数可以被称为 IQueryable。 GetJobs(int FranchiseID); 可以属于 FranchiseServiceJobServiceFranchiseService 是否应该充当 CatalogService (就像在 MVC Storefront 中一样)?

I'm building the 2nd iteration of a web-based CRM+CMS for a franchise service business in ASP.NET MVC 2. I need to control access to each franchise's services based on the roles a user is assigned for that franchise.

4 examples:

  • Receptionist should be able to book service jobs in for her "Atlantic Seaboard" franchise, but not do any reporting.
  • Technician should be able to alter service jobs, but not modify invoices.
  • Managers should be able to apply discount to invoices for jobs within their stores.
  • Owner should be able to pull reports for any franchises he owns.

Where should franchise-level access control fit in between the Data - Services - Web layer?
If it belongs in my Controllers, how should I best implement it?

Partial Schema

Roles class

int ID { get; set; } // primary key for Role
string Name { get; set; }

Partial Franchises class

short ID { get; set; } // primary key for Franchise
string Slug { get; set; } // unique key for URL access, eg /{franchise}/{job}
string Name { get; set; }

UserRoles mapping

short FranchiseID; // related to franchises table
Guid UserID; // related to Users table
int RoleID; // related to Roles table
DateTime ValidFrom;
DateTime ValidUntil;

Controller Implementation

Access Control with [Authorize] attribute

If there was just one franchise involved, I could simply limit access to a controller action like so:

[Authorize(Roles="Receptionist, Technician, Manager, Owner")]
public ActionResult CreateJob(Job job)
{
    ...
}

And since franchises don't just pop up over night, perhaps this is a strong case to use the new Areas feature in ASP.NET MVC 2? Or would this lead to duplicate Views?

Controllers, URL Routing & Areas

Assuming Areas aren't used, what would be the best way to determine which franchise's data is being accessed? I thought of this:

{franchise}/{controller}/{action}/{id}

or is it better to determine a job's franchise in a Details(...) action and limit a user's action with [Authorize]:

{job}/{id}/{action}/{subaction}
{invoice}/{id}/{action}/{subaction}

which makes more sense if any user could potentially have access to more than one franchise without cluttering the URL with a {franchise} parameter.

Any input is appreciated.

Edit:

Background

I built the previous CRM in classic ASP and it runs the business well, but it's time for an upgrade to speed up workflow and leave less room for error. For the sake of proper testing and better separation between data and presentation, I decided to implement the repository pattern as seen in Rob Conery's MVC Storefront series.

How to arrange services and repositories?

It makes sense to have a JobService that retrieves any service jobs based on available filters, eg. IQueryable<Job> GetJobs();. But since a job can only belong to one franchise, a function like IQueryable<Job> GetJobs(int franchiseID); could belong in either FranchiseService or in JobService. Should FranchiseService act as a CatalogService (like in MVC Storefront)?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

哆啦不做梦 2024-09-06 11:44:27

让我尝试回答一下这个问题。我正在使用一个涉及上述某些方面的示例应用程序。这不是权威答案,只是经验。

特许经营级访问控制应位于数据 - 服务 - Web 层之间的哪个位置?

此访问限制应该
渗透到您的申请中
两个级别 1) 数据库 2)
应用层。在 MVC 上下文中我
建议创建一个自定义
授权属性 - 这个句柄
Web 服务之间的安全性
层。我想让这个属性做
两件事

  1. 获取用户当前允许的角色(可以从数据库中获取)
    存储在用户会话中)
  2. 检查用户是否属于允许的角色列表。
    就数据库而言,这
    取决于你如何存储
    数据,所有特许经营的一个数据库
    或每个特许经营的数据库。在
    第一种情况有几种方法来限制
    并设置访问限制
    数据到特定的
    特许经营权。

由于特许经营权不会在一夜之间突然出现,也许这是使用 ASP.NET MVC 2 中新的 Areas 功能的一个强有力的案例?或者这会导致重复的视图?

我认为 Areas 应该用于
拆分和分组功能。如果你
是使用区域来分割特许经营权,
这是我看到重复的地方
视图、控制器等发生。复制
可以通过使用来克服观点
自定义视图引擎专门
覆盖 MVC 定位你的方式
意见。插件:请参阅我对 ASP.NET MVC:自定义设计的回答域

假设未使用区域,确定正在访问哪个特许经营权的数据的最佳方法是什么?

如上所述,您可以
用户会话存储基本信息
诸如特许经营权等信息
用户所属和角色等
分配的。我认为我读到的规则
某处沿着线
保护您的行为,而不是您的
控制器

为规范创建路线等
不是为了例外。例如。有没有
目前的一个商业案例说
用户可以访问多个
特许经营权?

如何安排服务和存储库?

拥有一组基础服务或基础
类将包含所有
特定信息所需的信息
特许经营权,例如 franchiseId
它解决的主要问题是
您的服务方式更加干净
没有 franchiseId 参数。
然而,存储库可能需要这个
价值,因为在某些时候你需要
消除数据的歧义
请求或存储(假设一个数据库
对于所有特许经营权)。然而,你
使用 IoC 可以克服其中的一些问题。

我看到的缺点是
他们总会接到电话
每次你的对象被数据库
创建(即如果特许经营权
要使用路线,您需要
去数据库获取
每次对应的franchiseId
您创建一个服务对象。 (我可能
在这一点上是错误的,因为国际奥委会
容器确实有一些生活方式
可能能够提供帮助的选项
防止这种情况发生)
你可以
已创建的特许经营列表
在你身上应用程序启动你
可以用来将您的路线值映射到
获取正确的信息。这
部分答案是分散的,但是
最主要的是国际奥委会会提供帮助
你解耦了很多依赖关系。

希望这有帮助..

Let me take a stab at answering this. I am in the process of playing with a sample app that touches some of the aspects mentioned. This is not an authoritative answer, merely experience.

Where should franchise-level access control fit in between the Data - Services - Web layer?

This access restrictions should
permeated through your application at
two levels 1) the database 2) the
application layer. In an MVC context I
would suggest having creating a custom
Authorization attribute - this handles
the security between the Web-Services
layer. I would have this attribute do
two things

  1. Get the current roles allowed for the user (either from the DB of it may
    be stored in the user session)
  2. Do the checking to see if the user is part of the allowed list of roles.
    With regards to the database, this
    depends on how you are storing the
    data, one database for all franchises
    or database per franchise. In the
    first case there are several ways to limit
    and setup access restrictions for
    data to a particular
    franchise.

Since franchises don't just pop up over night, perhaps this is a strong case to use the new Areas feature in ASP.NET MVC 2? Or would this lead to duplicate Views?

I think that Areas should be used to
split and group functionality. If you
were to use Areas to split franchises,
this is where I see a duplication of
views, controllers etc. occurring. Duplicate
views can be overcome by using a
custom view engine to specifically
overriding the way MVC locates your
views. Plug: See my answer to ASP.NET MVC: customized design per domain

Assuming Areas aren't used, what would be the best way to determine which franchise's data is being accessed?

As mentioned above, you could the
users session to store basic
information such as the franchise the
user belongs to and the roles etc
assigned. I think the rule I read
somewhere goes along the lines of
"Secure your actions, not your
controllers
"

Create you routes etc for the norm and
not for the exception. eg. Is there
currently a business case that says a
user can have access to more than one
franchise?

How to arrange services and repositories?

Have a set of base services or base
classes that will contain all the
information required for a particular
franchise such as the franchiseId.
Th main issue that it does resolve is
that your service methods are cleaner
not having the franchiseId argument.
The repository however may need this
value since as some point you need to
disambiguate the data you are
requesting or storing (assuming one db
for all franchises). However, you
could overcome some of this using IoC.

The downside I see is that
they there will always be calls to the
database every time your objects are
creating (i.e. if the franchise
route were to be used, you would need
to go the database to obtain the
corresponding franchiseId every time
you create a service object. ( I might
be mistaken on this one, since the IoC
containers do have some LifeStyle
options that may be able to assist and
prevent this)
You could have
a list of Franchises that are created
on you Application start that you
could use to map your route values to
obtain the correct information. This
part of the answer is scattered, but
the main thing is that IoC will help
you decouple a lot of dependencies.

Hope this helps..

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文