2011-08-25 54 views
1

我正在制作一个ASP.Net MVC3应用程序。我现在使用Visual Studio 2010项目附带的内置验证代码。问题是我需要在登录后立即检索登录用户的数据库ID。我现在通过向账户控制器的登录操作添加代码,通过用户名查找数据库来从数据库中检索ID 。这适用于新登录,但不适用于“已记住”的登录。在重新启动应用程序时,最后一个用户会自动再次登录,但登录代码不会被触发,所以我没有得到数据库ID。如何进入自动重复登录?

我该如何解决这个问题?

编辑: 我试图实现丹尼尔的解决方案,看起来很有前途,我想出了这个代码。它nevers被称为虽然!我哪里错了?

的Global.asax.cs:

protected void Application_Start() 
{ 
    Database.SetInitializer<StandInContext>(new StandInInitializer()); 

    AreaRegistration.RegisterAllAreas(); 

    RegisterGlobalFilters(GlobalFilters.Filters); 
    RegisterRoutes(RouteTable.Routes); 
    this.AuthenticateRequest += 
     new EventHandler(MvcApplication_AuthenticateRequest); 
} 

void MvcApplication_AuthenticateRequest(object sender, EventArgs e) 
{ 
    if(Request.IsAuthenticated) 
    { 
     using (var db = new StandInContext()) 
     { 
      var authenticatedUser = db.AuthenticatedUsers.SingleOrDefault(
       user => user.Username == User.Identity.Name); 
      if (authenticatedUser == null) 
       return; 
      var person = db.Persons.Find(authenticatedUser.PersonID); 
      if (person == null) 
       return; 

      Context.User = new CustomPrincipal(
          User.Identity, new string[] { "user" }) 
          { 
           Fullname = person.FullName, 
           PersonID = person.PersonID, 
          }; 
     } 
    } 
} 
+0

Dabblernl,那签名似乎不正确。尝试用'Application_AuthenticateRequest'替换'MvcApplication_AuthenticateRequest'并查看事件是否触发。 –

+0

@丹尼尔卢齐:谢谢,它现在有效。我只是不明白'Application_AuthenticateRequest'方法如何在不被注册为EventHandler或作为覆盖的情况下突然被调用。 – Dabblernl

+0

这就是AutoEventWireUp的魔力。这基本上可以节省你必须手动附加事件处理程序,如果你坚持方法命名的某种约定。看到[这个答案](http://stackoverflow.com/questions/4677866/global-asax-postauthenticaterequest-binding/4677905#4677905)一些更多的信息。 –

回答

3

你可以在你的Global.asax.cs使用AuthenticateRequest事件:

protected void Application_AuthenticateRequest() 
{ 
    if (Request.IsAuthenticated) 
    { 
     // retrieve user from repository 
     var user = _membershipService.GetUserByName(User.Identity.Name); 
     // do other stuff 
    } 
} 

更新:

现在,我明白了你试图做的更清楚一些,我会建议不要在这个特殊情况下使用会话。其中一个原因是会话需要参考System.Web,您无法从某些位置访问该位置,例如单独的类库中的业务逻辑层。另一方面,IPrincipal存在这个原因。

如果您需要存储比IPrincioal提供的更多用户信息,您只需实现它并添加您自己的属性。但更方便,你可以从GenericPrincipal派生,它实现IPrincipal的,并增加了一些基本的角色检查功能:

CustomPrincipal.cs

public class CustomPrincipal : GenericPrincipal 
{ 
    public CustomPrincipal(IIdentity identity, string[] roles) 
     : base(identity, roles) { } 

    public Guid Id { get; set; } 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
    public string Email { get; set; } 
    ... 
} 

,那么你替换为自己的默认本金AuthenticateRequest,像以前一样:

的Global.asax.cs

protected void Application_AuthenticateRequest() 
{ 
    if (Request.IsAuthenticated) 
     Context.User = _securityService.GetCustomPrincipal(User.Identity.Name); 
} 

就是这样。您获得的最大优势是您可以从字面上随处访问您的用户数据,而无需将参数粘贴到您的所有方法中。所有你需要做的就是投目前主要回CustomPrincipal,并访问您的数据,像这样:

从你的剃须刀的观点:

<p>Hello, @((CustomPrincipal)User).FirstName!</p> 

从你的控制器:

var firstName = ((CustomPrincipal)User).FirstName; 

从在另一个汇编中的业务逻辑层:

var firstName = ((CustomPrincipal)Thread.CurrentPrincipal).FirstName; 

要保持干燥,您可以打包是为扩展方法,并把它挂过的IPrincipal,像这样:

public static class PrincipalExtensions 
{ 
    public static string GetFirstName(this IPrincipal principal) 
    { 
     var customPrincipal = principal as CustomPrincipal; 
     return customPrincipal != null ? customPrincipal.FirstName : ""; 
    } 
} 

然后你就只是做@User.GetFirstName()var userName = User.GetFirstName()Thread.CurrentPrincipal.GetFirstName()

希望这有助于。

+0

对不起,我应该说清楚一点。 '_membership'和'_securityService'只是一个如何从数据库/存储库中获取数据的例子。您只需将它们替换为适用于从数据库中检索用户的任何逻辑即可。 –

1

我没有想清楚。我试图将用户信息存储在Session对象中,而它通过User对象可用。抱歉浪费你的时间。

+0

别担心,你不浪费任何人的时间:)看到我更新的答案。 –