ASP.NET MVC - 设置自定义的IIdentity或IPrincipal的 [英] ASP.NET MVC - Set custom IIdentity or IPrincipal

查看:816
本文介绍了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 在那里,这样也没有要走的路。

我一直在这一天,现在我觉得我失去了一些东西。这应该不是太难的事,对不对?我也是受了一点所有的(半)相关的附带这个东西混淆。 的MembershipProvider 的MembershipUser RoleProvider ProfileProvider 的IPrincipal 的IIdentity FormsAuthentication ....我是唯一一个谁认为这一切都非常混乱?

如果有人能告诉我一个简单,优雅,有效的解决方案来存储上的IIdentity一些额外的数据,而无需所有额外的绒毛..这将是伟大的!我知道有上如此相似的问题,但如果我需要的答案就在那里,我一定是忽略了。

解决方案

下面就是我如何做到这一点。

我决定,而不是使用的IIdentity IPrincipal的,因为这意味着我不必同时实现的IIdentity和IPrincipal的。


  1. 创建接口

     接口ICustomPrincipal:IPrincipal的
    {
        INT标识{搞定;组; }
        字符串名字{获得;组; }
        字符串名字{获得;组; }
    }


  2. CustomPrincipal

     公共类CustomPrincipal:ICustomPrincipal
    {
        公众的IIdentity身份{搞定;私人集; }
        公共BOOL IsInRole(字符串角色){返回false; }    公共CustomPrincipal(字符串email)
        {
            this.Identity =新GenericIdentity(电子邮件);
        }    公众诠释标识{搞定;组; }
        公共字符串名字{获得;组; }
        公共字符串名字{获得;组; }
    }


  3. CustomPrincipalSerializeModel - 序列化的自定义信息到用户数据领域的FormsAuthenticationTicket对象

     公共类CustomPrincipalSerializeModel
    {
        公众诠释标识{搞定;组; }
        公共字符串名字{获得;组; }
        公共字符串名字{获得;组; }
    }


  4. 登录方法 - 建立一个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(指数,家);
    }


  5. 的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;
        }
    }


  6. 在剃刀意见访问

      @((用户为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.

  1. Create the interface

    interface ICustomPrincipal : IPrincipal
    {
        int Id { get; set; }
        string FirstName { get; set; }
        string LastName { get; set; }
    }
    

  2. 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; }
    }
    

  3. 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; }
    }
    

  4. 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");
    }
    

  5. 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;
        }
    }
    

  6. 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆