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

我读过很多文章和问题,但我觉得我让事情变得比实际情况更难了.我以为这很容易.如果用户登录,我想设置一个自定义身份.所以我想,我将在全局实施Application_PostAuthenticateRequest.尽快.但是,在每个请求上都会调用它,我不想在每个请求上调用数据库,这会请求数据库中的所有数据,并将其放入一个定制的IPrincipal对象中.这似乎也非常不必要,速度很慢,而且在错误的地方(在那里进行数据库调用),但我可能错了.或者这些数据还会从哪里来?

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

我已经为此工作了一天,我觉得我错过了一些东西.这应该不难做到,对吧?我也有点困惑,所有(半)相关的东西,随之而来的.MembershipProvider, MembershipUser, RoleProvider, ProfileProvider, IPrincipal, IIdentity, FormsAuthentication.... 我是唯一一个觉得这一切都很困惑的人吗?

如果有人能告诉我一个简单、优雅和高效的解决方案来在IIdentity上存储一些额外的数据,而不会造成额外的混乱……那太好了!我知道上面有类似的问题,但如果我需要的答案就在那里,我一定是忽略了.

推荐答案

我是这样做的.

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

  1. 创建接口

    interface I客户主体 : IPrincipal
    {
        int Id { get; set; }
        string FirstName { get; set; }
        string LastName { get; set; }
    }
    
  2. 客户主体

    public class 客户主体 : I客户主体
    {
        public IIdentity Identity { get; private set; }
        public bool IsInRole(string role) { return false; }
    
        public 客户主体(string email)
        {
            this.Identity = new GenericIdentity(email);
        }
    
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }
    
  3. 客户主体SerializeModel - for serializing custom information into userdata field in FormsAuthenticationTicket object.

    public class 客户主体SerializeModel
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }
    
  4. 登录方法-使用自定义信息设置cookie

    if (Membership.ValidateUser(viewModel.Email, viewModel.Password))
    {
        var user = userRepository.Users.Where(u => u.Email == viewModel.Email).First();
    
        客户主体SerializeModel serializeModel = new 客户主体SerializeModel();
        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-读取cookie并替换HttpContext.User对象,这是通过重写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();
    
            客户主体SerializeModel serializeModel = serializer.Deserialize<客户主体SerializeModel>(authTicket.UserData);
    
            客户主体 newUser = new 客户主体(authTicket.Name);
            newUser.Id = serializeModel.Id;
            newUser.FirstName = serializeModel.FirstName;
            newUser.LastName = serializeModel.LastName;
    
            HttpContext.Current.User = newUser;
        }
    }
    
  6. 在Razor视图中访问

    @((User as 客户主体).Id)
    @((User as 客户主体).FirstName)
    @((User as 客户主体).LastName)
    

在代码中:

    (User as 客户主体).Id
    (User as 客户主体).FirstName
    (User as 客户主体).LastName

我认为代码是不言自明的.如果不是,请告诉我.

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

public class BaseController : Controller
{
    protected virtual new 客户主体 User
    {
        get { return HttpContext.User as 客户主体; }
    }
}

然后,对于每个控制器:

public class AccountController : BaseController
{
    // ...
}

这将允许您访问以下代码中的自定义字段:

User.Id
User.FirstName
User.LastName

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

public abstract class BaseViewPage : WebViewPage
{
    public virtual new 客户主体 User
    {
        get { return base.User as 客户主体; }
    }
}

public abstract class BaseViewPage<TModel> : WebViewPage<TModel>
{
    public virtual new 客户主体 User
    {
        get { return base.User as 客户主体; }
    }
}

在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>

在视图中,您可以这样访问它:

@User.FirstName
@User.LastName

Asp.net相关问答推荐

Stimulsoft 没有在智能手机中显示正确的 pdf 字体

Windows 命令行中的/p:是什么意思

DBSet 不包含 Where 的定义

是否可以发布 ASP.NET 5 应用程序以使目标机器不需要安装 DNX?

如何注册路由区域

Azure 自定义控制器/API .Net 后端

ASP.NET Response.Redirect 使用 302 而不是 301

Asp.net Identity 密码哈希

防止在 Visual Studio 2008 ASP.NET Web 窗体中复制粘贴时自动生成 ID

您如何在 .net WebApi2 应用程序中的 OAuth2 令牌请求中使用额外参数

用于呈现

禁用 web.config 继承?

ASP.NET MVC 和 httpRuntime executionTimeout

ContentResult 与字符串

在后面的代码中删除 css 类

好的 ASP.NET 类似 excel 的网格控件?

ASP.NET - 从静态方法/静态类访问会话?

在.net的内存数据库中

为什么 IFormFile 显示为空,我该如何解决?

静态变量是线程安全的吗? C#