3

我正在尝试改进我的 MVC 设计。在每个页面上,我都需要读取一个 cookie 并基于它设置一个具有各种值的 User 对象(与身份验证无关)。

我目前所做的是让所有控制器都从 BaseController 继承,并在 BaseController 中使用 User 对象。

public class BaseController : Controller
{
    protected User thisUser { get; private set; }

    protected override void Initialize(System.Web.Routing.RequestContext requestContext)
    {
         // ... read cookie, set values of thisUser
    }
}

这是一个糟糕的设计吗?我喜欢它只定义User一次,但我已经阅读了关于ASP.NET MVC 中的基控制器类有哪些好的候选者的答案?,如果有更好的方法,我愿意重做。但我绝对不想要一种意味着User thisUser = new User();在每个控制器上重复的方法,而且我看不出如果没有基本控制器我怎么能这样实现。我找不到以这种方式使用 ActionFilters 的好例子。

我还没有使用 DI 框架,但如果它解决了问题,我会。如果这意味着将User参数作为参数传递给每个控制器或动作,我不确定这是否是 DRY 赌注的改进。

我确定我缺少一些东西。任何帮助,将不胜感激...

4

1 回答 1

3

创建接口

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

自定义主体

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 UserId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

CustomPrincipalSerializeModel - 用于将自定义信息序列化到 FormsAuthenticationTicket 对象中的 userdata 字段中。

public class CustomPrincipalSerializeModel
{
    public int UserId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

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

if (Membership.ValidateUser(viewModel.Email, viewModel.Password))
{
    var user = userRepository.Users.Where(u => u.Email == viewModel.Email).First();

    CustomPrincipalSerializeModel serializeModel = new CustomPrincipalSerializeModel();
    serializeModel.UserId = 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 来完成的

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.UserId = serializeModel.UserId;
        newUser.FirstName = serializeModel.FirstName;
        newUser.LastName = serializeModel.LastName;

        HttpContext.Current.User = newUser;
    }
}

在 Razor 视图中访问

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

要获得完整答案,请使用此主题: ASP.NET MVC - Set custom IIdentity or IPrincipal

于 2013-02-04T12:37:56.327 回答