3

我正在尝试改进我的MVC设计。在每一页上,我需要读取一个cookie并根据该值设置具有各种值的用户对象(与身份验证无关)。如何用MVC ActionFilter(或其他)替换基础控制器?

我目前所做的是让所有控制器都从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一次,但我已阅读What are good candidates for base controller class in ASP.NET MVC?上的答案,如果有更好的方法,我愿意重做它。但我绝对不想要一种方法,即在每个控制器上重复User thisUser = new User();,并且我看不到如何在没有基础控制器的情况下实现这种功能。我找不到这样使用ActionFilters的好例子。

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

我确定有些东西我错过了。任何帮助,将不胜感激......

回答

3

创建接口

interface ICustomPrincipal : IPrincipal 
{ 
    int UserId { 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 UserId { get; set; } 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
} 

CustomPrincipalSerializeModel - 序列化的自定义信息到用户数据字段的FormsAuthenticationTicket对象。

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 - 读饼干和更换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; 
    } 
} 
完成

访问剃刀视图

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

为完整答案使用该主题: ASP.NET MVC - Set custom IIdentity or IPrincipal

+0

+1。但我会在我的'CustomPrincipal'中提供一个静态getter,它为我进行强制转换('public static CustomPrincipal Current get {return(CustomPrincipal)Thread.CurrentPrincipal;}}'),所以我只需要使用CustomPrincipal.Current。 LastName' – jgauffin

相关问题