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

查看:30
本文介绍了ASP.NET MVC - 设置自定义 IIdentity 或 IPrincipal的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要做一些相当简单的事情:在我的 ASP.NET MVC 应用程序中,我想设置一个自定义的 IIdentity/IPrincipal.哪个更容易/更合适.我想扩展默认值,以便我可以调用诸如 User.Identity.IdUser.Identity.Role 之类的东西.没什么特别的,只是一些额外的属性.

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.

我阅读了大量文章和问题,但我觉得我让它变得比实际更难.我以为这会很容易.如果用户登录,我想设置一个自定义的 IIdentity.所以我想,我将在我的 global.asax 中实现 Application_PostAuthenticateRequest.但是,这是在每个请求上调用的,我不想在每个请求上都调用数据库,这将请求数据库中的所有数据并放入自定义 IPrincipal 对象.这似乎也是非常不必要的、缓慢的并且在错误的地方(在那里进行数据库调用),但我可能是错的.或者这些数据来自哪里?

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?

所以我想,每当用户登录时,我都可以在我的会话中添加一些必要的变量,我将这些变量添加到 Application_PostAuthenticateRequest 事件处理程序中的自定义 IIdentity.但是,我的 Context.Session 在那里是 null,所以这也不是要走的路.

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.

我已经为此工作了一天,但我觉得我错过了一些东西.这应该不难做到吧?我也对随之而来的所有(半)相关内容感到有些困惑.MembershipProviderMembershipUserRoleProviderProfileProviderIPrincipalIIdentity, FormsAuthentication.... 只有我一个人觉得这一切很混乱吗?

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?

如果有人能告诉我一个简单、优雅和有效的解决方案,在 IIdentity 上存储一些额外的数据,而无需所有额外的模糊......那就太好了!我知道在 SO 上也有类似的问题,但如果我需要的答案就在那里,我一定是忽略了.

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.

推荐答案

这是我的做法.

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

I decided to use IPrincipal instead of IIdentity because it means I don't have to implement both IIdentity and IPrincipal.

  1. 创建界面

  1. 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 - 用于将自定义信息序列化到 FormsAuthenticationTicket 对象中的用户数据字段中.

  • 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; }
    }
    

  • 登录方法 - 使用自定义信息设置 cookie

  • 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 - 读取 cookie 并替换 HttpContext.User 对象,这是通过覆盖 PostAuthenticateRequest 来完成的

  • 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;
        }
    }
    

  • 在 Razor 视图中访问

  • Access in Razor views

    @((User as CustomPrincipal).Id)
    @((User as CustomPrincipal).FirstName)
    @((User as CustomPrincipal).LastName)
    

  • 并在代码中:

        (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.

    此外,为了使访问更加容易,您可以创建一个基本控制器并覆盖返回的用户对象 (HttpContext.User):

    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
    

    但这在视图中不起作用.为此,您需要创建一个自定义的 WebViewPage 实现:

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

    使其成为 Views/web.config 中的默认页面类型:

    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
    

    这篇关于ASP.NET MVC - 设置自定义 IIdentity 或 IPrincipal的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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