ASP.NET MVC 3 MembershipProvider

3

我目前正在使用ASP.NET MVC 3开发网站,使用Nhibernate。我创建了一个自定义的MembershipProvider,如下所述。

我的问题是,在ValidateUser方法中记录用户身份验证的时间并在GetUser中检索它的时间。

据我所知,您不能在ValidateUser中使用Session,但使用Cache也不正确,因为存储不是每个用户会话的。

我该怎么办?

class MyMembershipProvider : MembershipProvider
{
    public override MembershipUser GetUser(string username, bool userIsOnline)
    {
        var membershipUser = MyMembershipUser)HttpContext.Current.Cache.Get(username);

        // Is not possible
        // var membershipUser = (MyMembershipUser) HttpContext.Current.Session[username];

        return membershipUser;
    }

    public override bool ValidateUser(string username, string password)
    {
        var usuario = UsuarioRepository.GetUsuarioAuthentication(username, password);

        if (usuario != null)
        {
            HttpContext.Current.Cache.Add(username, new MyMembershipUser(usuario.Id, usuario.Email), null,
                                          Cache.NoAbsoluteExpiration, FormsAuthentication.Timeout,
                                          CacheItemPriority.Default, null);

            // Is not possible 
            // HttpContext.Current.Session.Add(username, new MyMembershipUser(usuario.Id, usuario.Email));

            return true;
        }

        return false;
    }

}


不要在ValidateUser方法中添加它。如果ValidateUser返回true,则在Web应用程序中同时添加它。 - TheGeekYouNeed
但是在 GetUser(string username, bool userIsOnline) 方法中,我需要返回一个 MembershipUser。 - Michel Andrade
4个回答

5

当您使用ASP.NET Membership与Forms身份验证时,会完全不涉及会话。

一旦用户成功通过身份验证,只需调用

FormsAuthentication.SetAuthCookie() 

并且一个身份验证cookie会自动为您创建。不要在ValidateUser()中调用它,而是从调用ValidateUser()的客户端代码中调用。

身份验证cookie与会话cookie完全独立。

有关更多信息,请参阅MSDN上的Forms身份验证

如果要缓存已验证用户的用户详细信息,则应该在调用Membership.ValidateUser()的客户端代码中完成,而不是在成员提供程序本身中完成。成员提供程序GetUser()和ValidateUser()应该按照其名称所示去做,不应具有任何其他副作用。


实际上,我正在使用自定义的 Membership(成员资格),这就是为什么要调用 GetUser 的原因。 - Michel Andrade
1
@Michel 无论您选择使用哪个成员资格提供程序,都适用相同的模式。您调用Membership.Validate(),然后如果成功,调用FormsAuthentication.SetAuthCookie()。 - saille
是的,Saille 是正确的。Session 在自定义成员资格提供程序中没有位置。在创建自定义成员资格提供程序之后,如果您真的需要,可以将其中一些信息存储在 Session 中。 - David East
我正在尝试做类似的事情。例如,在我的身份验证过程中,成功的身份验证将返回一些我想要存储在会话中的信息。但是由于会话尚未创建(直到我从该方法返回),因此会话为null。有没有办法从ValidateUser方法初始化会话? - Sinaesthetic
考虑使用ASP.NET Profile而不是Session作为用户特定信息的接口。 - saille

1
这两种方法的实现只需要查询数据库并返回一个MembershipUser或验证用户名密码-不必担心HttpContext。 我不知道您的UsuarioRepository实现的具体细节,因此我只是编写了一些方法,但是您应该大致按照以下方式编写提供程序:
class MyMembershipProvider : MembershipProvider
{
    public override MembershipUser GetUser(string username, bool userIsOnline)
    {
        var usuario = UsuarioRepository.GetUserByUserName(username);
        return new MyMembershipUser(usuario.Id, usuario.Email);
    }

    public override bool ValidateUser(string username, string password)
    {
        return UsuarioRepository.ValidateUser(username, password);              
    }
}

UsuarioRepository.GetUserByUserName(username) 方法将返回给定用户名的用户,而 UsuarioRepository.ValidateUser(username, password) 应该在给定用户名的情况下返回 true,如果密码正确。存储库将处理获取会话并执行查询。

然后,为了提高提供程序的性能,您可以使用 NHibernate 的一些内置缓存功能来确保它通过修改您的 UsuarioRepository 方法来使用缓存来缓存这些查询的结果。然后对这些方法的多次调用不会影响性能。


很好,那很完美,但是我的GetUser方法有时在单个请求中被调用了4次,这正常吗? - Michel Andrade
不,那不是正常的。你有在任何地方显式调用它吗?你的web.config文件中的membershipauthentication部分是什么样子的? - StanK
看起来还不错。因此,您为~/Login所采取的操作应将用户带到登录屏幕,并且该屏幕的POST应使用您的成员资格提供程序验证用户,如果用户经过身份验证,则应调用FormsAuthentication.SetAuthCookie(userName, createPersistentCookie),然后设置一个确认用户已获授权的cookie。 - StanK

1
你是否关心如何查找和存储用户信息?
使用MVC,您可以随时调用。
        User.Identity.Name

这将为您提供用户的当前用户名。

正如@Saille上面提到的,当创建自己的自定义成员资格提供程序时,您只需要关注创建MembershipUser和验证MembershipUser的基础知识。

完成基础知识并创建提供程序后,您可以在成功登录的情况下将信息存储到Session中。


1

您不想从会话中获取用户。GetUser 用于从数据库检索用户 - 返回填充的 MembershipUser 对象。


有没有其他的方法呢?如果请求调用这个方法两次或更多次呢? - Michel Andrade
如果在同一进程中调用了两次或更多次,那么您需要重新编写该代码。如果在应用程序中调用了两次或更多次,则没有问题。这就是为什么将Membership抽象成一个类的原因,因为您在多个地方使用它。 - David East
如果你只需要用户名,User.Identity.Name就可以了。如果你需要MembershipUser对象上的所有属性,你可以缓存该对象 - 使用用户名作为缓存键。我只能提出建议,因为我不知道你想要实现什么。 - TheGeekYouNeed

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接