ASP.NET MVC - 设置自定义 IIdentity 或 IPrincipal
我需要做一些相当简单的事情:在我的 ASP.NET MVC 应用程序中,我想设置一个自定义 IIdentity / IPrincipal。 哪个更容易/更合适。 我想扩展默认值,以便可以调用诸如 User.Identity.Id
和 User.Identity.Role
之类的内容。 没什么特别的,只是一些额外的属性。
我读过大量的文章和问题,但我觉得我让事情变得比实际更难。 我以为这很容易。 如果用户登录,我想设置一个自定义 IIdentity。 所以我想,我将在我的 global.asax 中实现 Application_PostAuthenticateRequest
。 但是,这是在每个请求上调用的,并且我不想在每个请求上调用数据库,这会请求数据库中的所有数据并放入自定义 IPrincipal 对象。 这似乎也非常不必要,缓慢,并且在错误的地方(在那里进行数据库调用),但我可能是错的。 或者这些数据还来自哪里?
所以我想,每当用户登录时,我都可以在会话中添加一些必要的变量,并将其添加到 Application_PostAuthenticateRequest
事件处理程序中的自定义 IIdentity 中。 但是,我的 Context.Session 是 null ,所以这也不是可行的方法。
我已经为此工作了一天,我觉得我错过了一些东西。 这应该不难做到,对吧? 我也对随之而来的所有(半)相关的东西感到有点困惑。 MembershipProvider
、MembershipUser
、RoleProvider
、ProfileProvider
、IPrincipal
、IIdentity< /code>,
FormsAuthentication
...我是唯一一个觉得这一切非常令人困惑的人吗?
如果有人可以告诉我一个简单、优雅且高效的解决方案来在 IIdentity 上存储一些额外的数据,而无需所有额外的模糊......那就太好了! 我知道也有类似的问题,但如果我需要的答案就在那里,我一定是忽略了。
I need to do something fairly simple: in my ASP.NET MVC application, I want to set a custom IIdentity / IPrincipal. Whichever is easier / more suitable. I want to extend the default so that I can call something like User.Identity.Id
and User.Identity.Role
. Nothing fancy, just some extra properties.
I've read tons of articles and questions but I feel like I'm making it harder than it actually is. I thought it would be easy. If a user logs on, I want to set a custom IIdentity. So I thought, I will implement Application_PostAuthenticateRequest
in my global.asax. However, that is called on every request, and I don't want to do a call to the database on every request which would request all the data from the database and put in a custom IPrincipal object. That also seems very unnecessary, slow, and in the wrong place (doing database calls there) but I could be wrong. Or where else would that data come from?
So I thought, whenever a user logs in, I can add some necessary variables in my session, which I add to the custom IIdentity in the Application_PostAuthenticateRequest
event handler. However, my Context.Session
is null
there, so that is also not the way to go.
I've been working on this for a day now and I feel I'm missing something. This shouldn't be too hard to do, right? I'm also a bit confused by all the (semi)related stuff that comes with this. MembershipProvider
, MembershipUser
, RoleProvider
, ProfileProvider
, IPrincipal
, IIdentity
, FormsAuthentication
.... Am I the only one who finds all this very confusing?
If someone could tell me a simple, elegant, and efficient solution to store some extra data on a IIdentity without all the extra fuzz.. that would be great! I know there are similar questions on SO but if the answer I need is in there, I must've overlooked.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
我不能直接谈论 ASP.NET MVC,但对于 ASP.NET Web 表单,技巧是创建一个
FormsAuthenticationTicket
并在用户通过身份验证后将其加密到 cookie 中。 这样,您只需调用数据库一次(或 AD 或您用于执行身份验证的任何内容),并且每个后续请求都将根据存储在 cookie 中的票证进行身份验证。关于此的一篇好文章:
http:// www.ondotnet.com/pub/a/dotnet/2004/02/02/ effectiveformsauth.html(损坏的链接)编辑:
由于上面的链接已损坏,我会在上面的回答中推荐 LukeP 的解决方案: https://stackoverflow.com/a/10524305 - 我还建议接受答案改为那个。
编辑2:
损坏链接的替代方法: https://web.archive.org/web/20120422011422/http://ondotnet.com/pub/a/dotnet/2004/02/02/ effectiveformsauth.html
I can't speak directly for ASP.NET MVC, but for ASP.NET Web Forms, the trick is to create a
FormsAuthenticationTicket
and encrypt it into a cookie once the user has been authenticated. This way, you only have to call the database once (or AD or whatever you are using to perform your authentication), and each subsequent request will authenticate based on the ticket stored in the cookie.A good article on this:
http://www.ondotnet.com/pub/a/dotnet/2004/02/02/effectiveformsauth.html(broken link)Edit:
Since the link above is broken, I would recommend LukeP's solution in his answer above: https://stackoverflow.com/a/10524305 - I would also suggest that the accepted answer be changed to that one.
Edit 2:
An alternative for the broken link: https://web.archive.org/web/20120422011422/http://ondotnet.com/pub/a/dotnet/2004/02/02/effectiveformsauth.html
这是完成工作的示例。 bool isValid 通过查看某些数据存储(假设您的用户数据库)来设置。 UserID 只是我维护的一个 ID。 您可以将电子邮件地址等其他信息添加到用户数据中。
在 golbal asax 中添加以下代码来检索您的信息。
当您稍后要使用该信息时,您可以按如下方式访问您的自定义主体。
这将允许您访问自定义用户信息。
Here is an example to get the job done. bool isValid is set by looking at some data store (lets say your user data base). UserID is just an ID i am maintaining. You can add aditional information like email address to user data.
in the golbal asax add the following code to retrive your information
When you are going to use the information later, you can access your custom principal as follows.
this will allow you to access custom user information.
MVC 为您提供了挂在控制器类上的 OnAuthorize 方法。 或者,您可以使用自定义操作过滤器来执行授权。 MVC 使它变得非常容易做到。 我在这里发布了一篇关于此的博客文章。 http://www.bradygaster.com/post/custom-authentication-with -mvc-3.0
MVC provides you with the OnAuthorize method that hangs from your controller classes. Or, you could use a custom action filter to perform authorization. MVC makes it pretty easy to do. I posted a blog post about this here. http://www.bradygaster.com/post/custom-authentication-with-mvc-3.0
如果您需要将某些方法连接到 @User 以在视图中使用,这里有一个解决方案。 没有任何严肃的会员定制的解决方案,但如果原始问题仅需要视图,那么这可能就足够了。 下面的代码用于检查从authorizefilter返回的变量,用于验证是否存在某些链接(不适用于任何类型的授权逻辑或访问授予)。
然后只需在 web.config 区域中添加引用,并在视图中像下面这样调用它。
Here is a solution if you need to hook up some methods to @User for use in your views. No solution for any serious membership customization, but if the original question was needed for views alone then this perhaps would be enough. The below was used for checking a variable returned from a authorizefilter, used to verify if some links wehere to be presented or not(not for any kind of authorization logic or access granting).
Then just add a reference in the areas web.config, and call it like below in the view.
基于LukeP的回答,并添加一些方法来设置
timeout
和requireSSL 与
Web.config
配合。参考链接
LukeP修改代码
1、根据
Web设置
。 FormsAuthentication.Timeout< /a> 将获取超时值,该值在 web.config 中定义。 我将以下内容封装为一个函数,该函数返回一个timeout
。配置ticket
。2、根据
RequireSSL
配置,配置cookie是否安全。Based on LukeP's answer, and add some methods to setup
timeout
andrequireSSL
cooperated withWeb.config
.The references links
Modified Codes of LukeP
1, Set
timeout
based onWeb.Config
. The FormsAuthentication.Timeout will get the timeout value, which is defined in web.config. I wrapped the followings to be a function, which return aticket
back.2, Configure the cookie to be secure or not, based on the
RequireSSL
configuration.如果您想简化页面隐藏代码中的访问,只需将以下代码添加到基页面并在所有页面中派生基页面:
作为 Web 表单用户(而非 MVC)的 LukeP 代码的补充, 您后面的代码可以简单地访问:
我在 Web 表单场景中缺少的是如何在未绑定到页面的代码中获得相同的行为,例如在 httpmodules 中,我应该始终添加在每个班级中演员,还是有更聪明的方法来获得这个?
感谢您的回答并感谢 LukeP,因为我使用您的示例作为我的自定义用户的基础(现在有
User.Roles
、User.Tasks
、User .HasPath(int)
、User.Settings.Timeout
和许多其他好东西)As an addition to LukeP code for Web Forms users (not MVC) if you want to simplify the access in the code behind of your pages, just add the code below to a base page and derive the base page in all your pages:
So in your code behind you can simply access:
What I'm missing in a Web Form scenario, is how to obtain the same behaviour in code not tied to the page, for example in httpmodules should I always add a cast in each class or is there a smarter way to obtain this?
Thanks for your answers and thank to LukeP since I used your examples as a base for my custom user (which now has
User.Roles
,User.Tasks
,User.HasPath(int)
,User.Settings.Timeout
and many other nice things)好吧,所以我是一个严肃的密码管理员,通过拖出这个非常古老的问题,但是有一个更简单的方法来解决这个问题,上面的@Baserz 已经提到了。 那就是使用 C# 扩展方法和缓存的组合(不要使用会话)。
事实上,微软已经在
Microsoft.AspNet.Identity.IdentityExtensions
命名空间。 例如,GetUserId()
是一个返回用户 ID 的扩展方法。 还有GetUserName()
和FindFirstValue()
,它们返回基于 IPrincipal 的声明。因此,您只需包含命名空间,然后调用 User.Identity.GetUserName() 即可获取 ASP.NET Identity 配置的用户名。
我不确定这是否被缓存,因为旧的 ASP.NET Identity 不是开源的,而且我也懒得对其进行逆向工程。 但是,如果不是,那么您可以编写自己的扩展方法,该方法会将此结果缓存特定的时间。
All right, so i'm a serious cryptkeeper here by dragging up this very old question, but there is a much simpler approach to this, which was touched on by @Baserz above. And that is to use a combination of C# Extension methods and caching (Do NOT use session).
In fact, Microsoft has already provided a number of such extensions in the
Microsoft.AspNet.Identity.IdentityExtensions
namespace. For instance,GetUserId()
is an extension method that returns the user Id. There is alsoGetUserName()
andFindFirstValue()
, which returns claims based on the IPrincipal.So you need only include the namespace, and then call
User.Identity.GetUserName()
to get the users name as configured by ASP.NET Identity.I'm not certain if this is cached, since the older ASP.NET Identity is not open sourced, and I haven't bothered to reverse engineer it. However, if it's not then you can write your own extension method, that will cache this result for a specific amount of time.
我尝试了LukeP建议的解决方案,发现它不支持Authorize属性。 所以,我稍微修改了一下。
最后在 Global.asax.cs
现在我可以通过调用来访问视图和控制器中的数据要注销
我只需调用
AuthManager 所在的位置
I tried the solution suggested by LukeP and found that it doesn't support the Authorize attribute. So, I modified it a bit.
And finally in Global.asax.cs
Now I can access the data in views and controllers simply by calling
To log out I just call
where AuthManager is
我是这样做的。
我决定使用 IPrincipal 而不是 IIdentity,因为这意味着我不必同时实现 IIdentity 和 IPrincipal。
创建界面
CustomPrincipal
CustomPrincipalSerializeModel - 用于将自定义信息序列化到 FormsAuthenticationTicket 对象中的 userdata 字段中。
登录方法 - 使用自定义信息设置 cookie
Global.asax.cs - 读取 cookie 并替换 HttpContext.User 对象,这是通过重写 PostAuthenticateRequest 来完成的
在 Razor 视图中访问
来 完成的
和代码中访问:
我认为代码是不言自明的。 如果不是,请告诉我。
此外,为了使访问更加容易,您可以创建一个基本控制器并覆盖返回的 User 对象(HttpContext.User):
然后,对于每个控制器:
这将允许您访问代码中的自定义字段,如下所示:
但这不起作用内部视图。 为此,您需要创建一个自定义 WebViewPage 实现:
使其成为 Views/web.config 中的默认页面类型:
并且在视图中,您可以像这样访问它:
Here's how I do it.
I decided to use IPrincipal instead of IIdentity because it means I don't have to implement both IIdentity and IPrincipal.
Create the interface
CustomPrincipal
CustomPrincipalSerializeModel - for serializing custom information into userdata field in FormsAuthenticationTicket object.
LogIn method - setting up a cookie with custom information
Global.asax.cs - Reading cookie and replacing HttpContext.User object, this is done by overriding PostAuthenticateRequest
Access in Razor views
and in code:
I think the code is self-explanatory. If it isn't, let me know.
Additionally to make the access even easier you can create a base controller and override the returned User object (HttpContext.User):
and then, for each controller:
which will allow you to access custom fields in code like this:
But this will not work inside views. For that you would need to create a custom WebViewPage implementation:
Make it a default page type in Views/web.config:
and in views, you can access it like this: