ASP.NET MVC - 设置自定义的IIdentity或IPrincipal的 [英] ASP.NET MVC - Set custom IIdentity or IPrincipal
问题描述
我需要做的事情很简单:在我的ASP.NET MVC应用程序,我想设置自定义的IIdentity / IPrincipal的。较容易/更适合。我想要扩展默认值,以便我可以调用类似 User.Identity.Id
和 User.Identity.Role
。没有什么花哨,只是一些额外的属性。
我读过吨的文章和问题,但我觉得我变得更难比它实际上是。我认为这会很容易。如果一个用户登录时,我想设置自定义的IIdentity。所以我想,我会在我的Global.asax实施 Application_PostAuthenticateRequest
。然而,被称为在每次请求,我不想做数据库调用每一个这将请求从数据库中的所有数据,并把一个自定义的IPrincipal对象请求。这也似乎很不必要的,缓慢的,在错误的地方(在做数据库调用有),但我可能是错的。或者还有什么地方会是从哪里来的数据?
所以我想,只要用户登录时,我可以添加在我的会议上,一些必要的变量,我增加了 Application_PostAuthenticateRequest
事件处理程序,自定义的IIdentity。然而,我的 Context.Session
是空
在那里,这样也没有要走的路。
我一直在这一天,现在我觉得我失去了一些东西。这应该不是太难的事,对不对?我也是受了一点所有的(半)相关的附带这个东西混淆。 的MembershipProvider
,的MembershipUser
, RoleProvider
, ProfileProvider
,的IPrincipal
,的IIdentity
, FormsAuthentication
....我是唯一一个谁认为这一切都非常混乱?
如果有人能告诉我一个简单,优雅,有效的解决方案来存储上的IIdentity一些额外的数据,而无需所有额外的绒毛..这将是伟大的!我知道有上如此相似的问题,但如果我需要的答案就在那里,我一定是忽略了。 P>
下面就是我如何做到这一点。
我决定,而不是使用的IIdentity IPrincipal的,因为这意味着我不必同时实现的IIdentity和IPrincipal的。
-
创建接口
接口ICustomPrincipal:IPrincipal的
{
INT标识{搞定;组; }
字符串名字{获得;组; }
字符串名字{获得;组; }
} -
CustomPrincipal
公共类CustomPrincipal:ICustomPrincipal
{
公众的IIdentity身份{搞定;私人集; }
公共BOOL IsInRole(字符串角色){返回false; } 公共CustomPrincipal(字符串email)
{
this.Identity =新GenericIdentity(电子邮件);
} 公众诠释标识{搞定;组; }
公共字符串名字{获得;组; }
公共字符串名字{获得;组; }
} -
CustomPrincipalSerializeModel - 序列化的自定义信息到用户数据领域的FormsAuthenticationTicket对象
公共类CustomPrincipalSerializeModel
{
公众诠释标识{搞定;组; }
公共字符串名字{获得;组; }
公共字符串名字{获得;组; }
} -
登录方法 - 建立一个cookie自定义信息
如果(Membership.ValidateUser(viewModel.Email,viewModel.Password))
{
VAR用户= userRepository.Users.Where(U => u.Email == viewModel.Email)。首先(); CustomPrincipalSerializeModel serializeModel =新CustomPrincipalSerializeModel();
serializeModel.Id = user.Id;
serializeModel.FirstName = user.FirstName;
serializeModel.LastName = user.LastName; 串行的JavaScriptSerializer =新的JavaScriptSerializer(); 字符串用户数据= serializer.Serialize(serializeModel); 的FormsAuthenticationTicket authTicket =新的FormsAuthenticationTicket(
1,
viewModel.Email,
DateTime.Now,
DateTime.Now.AddMinutes(15),
假,
用户数据); 字符串encTicket = FormsAuthentication.Encrypt(authTicket);
的HttpCookie faCookie =新的HttpCookie(FormsAuthentication.FormsCookieName,encTicket);
Response.Cookies.Add(faCookie); 返回RedirectToAction(指数,家);
} -
的Global.asax.cs - 读饼干和更换HttpContext.User中的对象,这是通过覆盖PostAuthenticateRequest完成
保护无效Application_PostAuthenticateRequest(对象发件人,EventArgs的发送)
{
的HttpCookie authCookie = Request.Cookies时[FormsAuthentication.FormsCookieName] 如果(authCookie!= NULL)
{
的FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value); 串行的JavaScriptSerializer =新的JavaScriptSerializer(); CustomPrincipalSerializeModel serializeModel = serializer.Deserialize< CustomPrincipalSerializeModel>(authTicket.UserData); CustomPrincipal NEWUSER =新CustomPrincipal(authTicket.Name);
newUser.Id = serializeModel.Id;
newUser.FirstName = serializeModel.FirstName;
newUser.LastName = serializeModel.LastName; HttpContext.Current.User = NEWUSER;
}
} -
在剃刀意见访问
@((用户为CustomPrincipal).ID)
@((用户为CustomPrincipal).FirstName)
@((用户为CustomPrincipal).LastName)
在code:
(用户为CustomPrincipal).ID
(用户为CustomPrincipal).FirstName
(用户为CustomPrincipal).LastName
我觉得code是不言自明的。如果不是,让我知道。
此外,使访问更容易,你可以创建一个基本的控制器,并覆盖返回的用户对象(HttpContext.User中):
公共类BaseController:控制器
{
受保护的虚拟新CustomPrincipal用户
{
{返回HttpContext.User中为CustomPrincipal; }
}
}
和然后,为每个控制器:
公共类的AccountController:BaseController
{
// ...
}
这将允许您访问code自定义字段是这样的:
User.Id
User.FirstName
User.LastName
不过,这不会在里面工作的意见。对于您需要创建一个自定义WebViewPage实现:
公共抽象类BaseViewPage:WebViewPage
{
公共虚拟新CustomPrincipal用户
{
{返回base.User为CustomPrincipal; }
}
}公共抽象类BaseViewPage<&的TModel GT; :WebViewPage<&的TModel GT;
{
公共虚拟新CustomPrincipal用户
{
{返回base.User为CustomPrincipal; }
}
}
请它查看默认的页面类型/ web.config中:
<页面pageBaseType =Your.Namespace.BaseViewPage>
<&命名空间GT;
<添加命名空间=System.Web.Mvc/>
<添加命名空间=System.Web.Mvc.Ajax/>
<添加命名空间=System.Web.Mvc.Html/>
<添加命名空间=System.Web.Routing/>
< /命名空间>
< /页>
和意见,你可以这样访问:
@ User.FirstName
@ User.LastName
心连心
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.
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
interface ICustomPrincipal : IPrincipal { int Id { get; set; } string FirstName { get; set; } string LastName { get; set; } }
CustomPrincipal
public class CustomPrincipal : ICustomPrincipal { public IIdentity Identity { get; private set; } public bool IsInRole(string role) { return false; } public CustomPrincipal(string email) { this.Identity = new GenericIdentity(email); } public int Id { get; set; } public string FirstName { get; set; } public string LastName { get; set; } }
CustomPrincipalSerializeModel - for serializing custom information into userdata field in FormsAuthenticationTicket object.
public class CustomPrincipalSerializeModel { public int Id { get; set; } public string FirstName { get; set; } public string LastName { get; set; } }
LogIn method - setting up a cookie with custom information
if (Membership.ValidateUser(viewModel.Email, viewModel.Password)) { var user = userRepository.Users.Where(u => u.Email == viewModel.Email).First(); CustomPrincipalSerializeModel serializeModel = new CustomPrincipalSerializeModel(); serializeModel.Id = user.Id; serializeModel.FirstName = user.FirstName; serializeModel.LastName = user.LastName; JavaScriptSerializer serializer = new JavaScriptSerializer(); string userData = serializer.Serialize(serializeModel); FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket( 1, viewModel.Email, DateTime.Now, DateTime.Now.AddMinutes(15), false, userData); string encTicket = FormsAuthentication.Encrypt(authTicket); HttpCookie faCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket); Response.Cookies.Add(faCookie); return RedirectToAction("Index", "Home"); }
Global.asax.cs - Reading cookie and replacing HttpContext.User object, this is done by overriding PostAuthenticateRequest
protected void Application_PostAuthenticateRequest(Object sender, EventArgs e) { HttpCookie authCookie = Request.Cookies[FormsAuthentication.FormsCookieName]; if (authCookie != null) { FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value); JavaScriptSerializer serializer = new JavaScriptSerializer(); CustomPrincipalSerializeModel serializeModel = serializer.Deserialize<CustomPrincipalSerializeModel>(authTicket.UserData); CustomPrincipal newUser = new CustomPrincipal(authTicket.Name); newUser.Id = serializeModel.Id; newUser.FirstName = serializeModel.FirstName; newUser.LastName = serializeModel.LastName; HttpContext.Current.User = newUser; } }
Access in Razor views
@((User as CustomPrincipal).Id) @((User as CustomPrincipal).FirstName) @((User as CustomPrincipal).LastName)
and in code:
(User as CustomPrincipal).Id
(User as CustomPrincipal).FirstName
(User as CustomPrincipal).LastName
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):
public class BaseController : Controller
{
protected virtual new CustomPrincipal User
{
get { return HttpContext.User as CustomPrincipal; }
}
}
and then, for each controller:
public class AccountController : BaseController
{
// ...
}
which will allow you to access custom fields in code like this:
User.Id
User.FirstName
User.LastName
But this will not work inside views. For that you would need to create a custom WebViewPage implementation:
public abstract class BaseViewPage : WebViewPage
{
public virtual new CustomPrincipal User
{
get { return base.User as CustomPrincipal; }
}
}
public abstract class BaseViewPage<TModel> : WebViewPage<TModel>
{
public virtual new CustomPrincipal User
{
get { return base.User as CustomPrincipal; }
}
}
Make it a default page type in Views/web.config:
<pages pageBaseType="Your.Namespace.BaseViewPage">
<namespaces>
<add namespace="System.Web.Mvc" />
<add namespace="System.Web.Mvc.Ajax" />
<add namespace="System.Web.Mvc.Html" />
<add namespace="System.Web.Routing" />
</namespaces>
</pages>
and in views, you can access it like this:
@User.FirstName
@User.LastName
HTH
这篇关于ASP.NET MVC - 设置自定义的IIdentity或IPrincipal的的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!