我有一个网站,其中有一个需要身份验证的区域。现在,我在该区域的所有控制器上使用角色属性,并运行查询来检索该用户 ID 及其所有设置。
对我来说,每次加载该区域的控制器时我都会检索用户 ID 和设置,这似乎是代码或设计的味道?我不确定是否应该使用会话,或者 ASP.Net MVC 2.0 是否提供了一些独特的方法来处理这个问题。另一个问题是安全性。
总的来说,我真的不知道该走哪条路。在设计方面,我希望用户登录该区域时仅检索一次用户 ID 和设置。现在,每次控制器加载时,我都会获取 userId,然后如果需要,我也会每次查询数据库以获取其设置。
I have a site which has an area that requires authentication. Right now I use the roles attribute on all the controllers in that area, and I run a query to retrieve that users ID, and all their settings.
It seems like a code or design smell to me that I am retrieving the userid and settings each time a controller in that area loads up? I'm not sure if I should be using sessions, or if ASP.Net MVC 2.0 provides some unique way to handle this. Another concern is security.
Overall, I don't really know which way to turn. Design wise I would like the userId and settings retrieved only once when the user logs into the area. Right now I grab the userId each time a controller loads up, and then if required, I query the database for their settings each time as well.
发布评论
评论(6)
关于安全的规则之一是您不应该尝试自己做这件事。正确地建立一个认证系统而不留下漏洞或后门有很多陷阱。因此,在这方面,您可能会考虑.NET 附带的 SqlMembershipProvider。它可以与 MVC 一起使用,并提供获取角色和当前安全上下文的方法,易于设置和配置,并且比您自己构建更安全。
如果您不使用 SQL Server,您有多种选择。一种解决方案是使用 SQL Server Express 或 SQL Server Compact Edition 之类的工具来维护凭据。另一种解决方案是模仿 SqlMembrershipProvider 数据库架构,然后编写与该架构通信的自定义提供程序。
最后的选择是编写一个自定义的 MembershipProvider 类。虽然这仍然是您自己的事情,但它会强制您进入 MembershipProvider 的结构,以便您可以在以后将其替换为不同的结构(例如 ActiveDirectoryMembershipProvider),并提供一个用于与凭据和登录进行交互的通用接口,例如可以轻松使用内置登录控件。
如果您已经在使用 MembershipProvider 并询问如何存储其他特定于用户的数据,那么我建议使用 SqlProfileProvider 以及我上面提到的有关 SqlMembershipProvider 的所有注意事项。 ProfileProvider 提供了一个结构,用于维护当前登录用户的特定于用户的数据。
有关详细信息:
One of the rules about security is that you shouldn't try to do it yourself. There are many pitfalls in doing an authentication system correctly without leaving loopholes or backdoors. Thus, in that regard, you might consider the SqlMembershipProvider that comes with .NET. It can be used with MVC and provides the means to get roles and the current security context, is easy to setup and configure and will be more secure than rolling your own.
If you are not using SQL Server, you have a couple of choices. One solution would be to use something like SQL Server Express or SQL Server Compact Edition to maintain the credentials. Another solution would be to mimic the SqlMembrershipProvider database schema and then write a custom provider that communicates with that schema.
The last choice would be to write a custom MembershipProvider class. While this is still rolling your own, it forces you into the structure of the MembershipProvider so that you can swap it out at a later date for a different one (e.g. ActiveDirectoryMembershipProvider) and provides a common interface for interacting with credentials and logins which for example enables easy use of the built-in Login control.
If you are already using a MembershipProvider and are asking about storing additional user-specific data, then I would suggest the SqlProfileProvider with all the caveats I mentioned above about the SqlMembershipProvider. the ProfileProvider provides a structure for maintain user-specific data with the currently logged on user.
For more information:
您还可以实现自定义身份。它们非常容易实现,并且允许您在 Identity 中存储所需的任何用户信息,然后将其存储在 Identity 放置的 cookie 中,因此您不必每次都访问数据库来获取该信息。
只需创建一个继承自 GenericIdentity 的新类,就可以了。
当然,您必须小心放在那里的信息量,因为它位于 cookie 中,但通常,您在这里讨论的情况下的用户相关信息并不是那么大。
我们使用自定义身份来存储有关用户的一些信息,效果非常好。
You could also implement a custom identity. They are very easy to implement, and they let you store whatever user information you want in Identity, which is then stored in the cookies that Identity puts down, so you're not hitting the DB every time to get that info.
Just create a new class that inherits from GenericIdentity, and you'll be on your way.
You of course have to be careful how much info you put there since it's in a cookie, but usually user related information in the case you're talking about here isn't so big.
We use a custom identity to store a few bits of info about the user, and it works out pretty well.
您可以在会话中存储一个对象来保存所有必需的用户信息。您只需在要检索用户信息/配置文件的控制器、视图或其他基类中添加一个属性。这将是授权信息,而不是任何身份验证信息(例如表单身份验证)
You could store an object in session that holds all the required user information. You will just need to add a property in the Controllers, Views or other base classes where you want to retrieve the user information/profile. This would be the authorisation info as opposed to any authentication info (eg Forms authentication)
您可以尝试“Windows Identity Foundation”。我已经在我的一个项目中使用它有一段时间了。它允许“基于声明的身份验证”,这基本上意味着您可以指定“声明”,即在用户登录时描述用户的信息字符串。
登录后,可以从
HttpContext.Current.User
字段读取用户的声明。您还可以使用与基于角色的身份验证模式无缝集成的“角色”声明;这意味着您可以为用户提供“经理”角色声明,然后使用 `if (User.IsInRole("manager"))。作为额外的好处,WIF 使您可以轻松地在其他应用程序中重复使用您的登录屏幕。
总而言之,它非常灵活,但文档非常差。我在 StackOverflow 上提出并回答了一些有关“Windows Identity Foundation”的问题。
You might try "Windows Identity Foundation". I've been using it on one of my projects for a while. It allows for "claims-based authentication", which basically means that you get to designate "claims", strings of information that describe the user when she logs on.
Once logged on, the user's claims can be read from the
HttpContext.Current.User
field. You can also use "Role" claims that seamlessly integrate with a role-based authentication schema; meaning that you can give the user a "manager" role claim and then use `if (User.IsInRole("manager")).As an added bonus, WIF makes it very easy to re-use your login screen in other applications.
All in all, it's very flexible, but the documentation is very poor. I've asked and answered a number of questions about "Windows Identity Foundation" on StackOverflow.
过去我们已经这样做过好几次了。与 Thomas 提到的类似,我们通常所做的就是基于 Microsoft SQL Memberhsip 提供程序实现一个新的 Membership 提供程序来执行此操作。我们从 MembershipUser 基类继承,并添加我们想要在用户对象上拥有的任何自定义属性。您必须在 GetUser 实现上为成员资格提供程序实现数据库读取,以便您可以将所需的额外属性合并到该数据库读取中。
如果您使用 SQL Server,Microsoft 已经发布了它的 2.0 代码。您可以在 Scott Gu 的博客中获取更多信息。
http://weblogs.asp.net/scottgu/archive/ 2006/04/13/442772.aspx
如果您想从头开始,MSDN 上也有很好的资源。
http://msdn.microsoft.com/en-us/library/f1kyba5e。 aspx
和
http://msdn.microsoft.com/en- us/library/6tc47t75.aspx
实现提供程序后,您可以将 Membership 用户添加到当前 Web 上下文的 Items 集合中,以便从您的代码中访问它。基本用户类中的非扩展属性也可以像平常一样在请求线程上使用。
随着微软发布2.0版本的源代码,我们发现它帮助我们减轻了一些关于重新发明的担忧。实现时要考虑的另一件事是根据您的场景,您可以绕过某些代码的实现。如果您访问的后端系统已经具有凭据信息,则 CreateUser 代码就是一个示例。
We have done this quite a few times in the past. Similar to what Thomas mentions, what we have generally done is implemented a new Membership provider based on the Microsoft SQL Memberhsip provider to do this. We inherit from the base MembershipUser class and add any custom properties we would want to have on the user object. You have to implement a database read for the Membership provider on the GetUser implementation, so you can consolidate your extra properties you need into that database read.
If you are using SQL server, Microsoft has release the 2.0 code for it. You can get more information at Scott Gu's blog.
http://weblogs.asp.net/scottgu/archive/2006/04/13/442772.aspx
If you want to start from scratch, they also have good resources at MSDN.
http://msdn.microsoft.com/en-us/library/f1kyba5e.aspx
and
http://msdn.microsoft.com/en-us/library/6tc47t75.aspx
Once you have implemented your provider, you can then add the Membership user to the Items collection of the current web context to get access to it from your code. The non extended properties from the base base user class are also available on the Request thread like normal.
With the Microsoft release of the 2.0 version of the source code , we found it helped us alleviate some concerns that exist about reinventing. Another thing to consider for your implementations is based on your scenario, you can bypass implementing some of the code. An example of this would be the CreateUser code if you are hitting a back end system that already has the credential information.
您似乎对身份验证过程相对满意,但您想探索会话/设置的其他选项。
我的建议仅与设置有关(角色、首选项等)。
在我看来,必须遍历从 UI 到业务层到 DB 层再到 DB 的整个技术堆栈有时有点矫枉过正。
对于在会话期间不太可能更改的数据,这会增加大量开销...可能会发生多种数据转换(DB(关系格式)-> ORM -> Web 服务 XML 序列化 -> Web层反序列化)。
您可能会考虑不依赖于重型 RDBMS 系统或 ASP.NET 缓存/会话模型的会话系统。有些选项性能非常好并且可扩展。
您可以使用 Ayende Rahien 的 RavenDB(专为 .NET 构建)。其主要目标是提供对无模式 JSON 文档的低延迟、高性能访问。
使用此解决方案,您可以在 Web 层设置 ravenDB,以便非常快速地访问数据。
第一次验证和检索设置时,您会将用户 ID 和设置信息存储在此会话数据库中。
此后每次加载控制器时,都可以访问设置数据,而无需返回 RDBMS。
该数据库还可用于缓存其他网络相关数据。
就安全性而言,无论您使用哪种方法,设置数据都会进入 Web 层。该解决方案的安全性不会比其他选项高或低(比未加密的 cookie 更安全)。如果需要,您可以加密会话数据 - 但这会再次增加您的开销。
这只是需要考虑的数百万个选项中的另一个。
祝你好运,
让我们知道你的决定!
帕特里克.
It seems like you're relatively happy with your authentication process but you want to explore other options for session/settings.
My suggestion has to do with settings only (roles, preferences, etc.)
In my opinion, having to traverse the whole technology stack from UI to Business Tier to DB tier to DB is sometimes a bit overkill.
For data that isn't likely to change during a session, this adds a lot of overhead... There are potentially several data transformations happening (DB (Relational Format) -> ORM -> Web Service XML Serialization -> Web Tier deserialization).
You might consider a session system that doesn't rely on a heavy RDBMS system or on the ASP.NET Caching / Session model. There are options that are very performant and that scale well.
You could use RavenDB by Ayende Rahien (Built for .NET). Its main goal is to provide low latency, high performance access to schema-less JSON documents.
Using this solution, you would set up ravenDB in the web tier so that access to data is very quick.
The first time you authenticate and retrieve settings, you would store the userID and settings information in this session DB.
Every time you load your controller after that, the settings data is accessible without having to go back to the RDBMS.
This DB could also be used to cache other web related data.
As for security, the settings data makes it to the web tier regardless of the method you use. This solution would be no more or less secure than the other options (more secure than an unencrypted cookie). If you needed to, you could encrypt the session data - but that will increase your overhead again.
Just another one of the million options to consider.
Good Luck,
Let us know what you decide!
Patrick.