Stack Overflow这样的网站如何在ASP.NET MVC中传递用户信息?

时间:2009-04-22 23:06:08

标签: asp.net-mvc user-controls openid

基本上,我使用OpenId登录我的网站,非常类似于我所假设的那样。当我收到信息后,我把它扔进一个数据库并创建我的“注册用户”。我设置了AuthCookie:

FormsAuthentication.SetAuthCookie(user.Profile.MyProfile.DisplayName, false);

然后我可以将它用作用户名。但是,我想传入整个对象而不仅仅是显示名称的字符串。所以我的问题是:

SO如何做到这一点?

他们是否会扩展/覆盖SetAuthCookie(string, bool)方法以接受用户对象,即SetAuthCookie(User(object), bool)

保留User对象的最佳方法是什么,以便我的Web应用程序的每个页面上的UserControl都可以使用它?

提前致谢!

3 个答案:

答案 0 :(得分:3)

您可以通过implementing自定义Membership Provider或扩展现有的MembershipUser来实现此行为。提供程序根据密钥(或仅通过用户名)存储用户信息,并提供对{{3}}类的访问权限,您可以根据需要进行扩展。因此,当您致电FormsAuthentication.SetAuthCookie(...)时,您基本上设置了用户密钥,可以通过提供商进行访问。

当您致电Membership.GetUser()时,会员基础设施将调用基础提供商并调用其GetUser(...)方法,为其提供当前用户的密钥。因此,您将收到当前的用户对象。

答案 1 :(得分:2)

杰夫,

正如我在上述问题的评论中所说,必须使用ClaimedIdentifier作为用户名 - 也就是SetAuthCookie的第一个参数。这有一个巨大的安全原因。如果您想了解更多有关原因的信息,请随时在dotnetopenid@googlegroups.com上发布主题。

现在关于整个用户对象的问题...如果你想把它作为一个cookie发送,你必须将你的用户对象序列化为字符串,然后你必须以某种方式签名防止用户篡改。您可能还想加密它。 Blah blah,这是一项很多工作,你最终会得到一个大的cookie来回传递你不想要的每个网页请求。

我在我的应用上为解决您所述的问题所做的是在我的Global.asax.cs文件中添加一个名为CurrentUser的静态属性。像这样:

public static User CurrentUser {
    get {
        User user = HttpContext.Current.Items["CurrentUser"] as User;
        if (user == null && HttpContext.Current.User.Identity.IsAuthenticated) {
            user = Database.LookupUserByClaimedIdentifier(HttpContext.Current.User.Identity.Name);
            HttpContext.Current.Items["CurrentUser"] = user;
        }
        return user;
    }
}

注意我将结果缓存在HttpContext.Current.Items字典中,该字典特定于单个HTTP请求,并且将用户提取保持为单次命中 - 并且仅在页面实际需要时才第一次获取它CurrentUser信息。

因此,页面可以轻松获取当前登录的用户信息,如下所示:

User user = Global.CurrentUser;
if (user != null) { // unnecessary check if this is a page that users must be authenticated to access
    int age = user.Age; // whatever you need here
}

答案 2 :(得分:1)

一种方法是向控制器注入一个类,该类负责检索当前登录用户的信息。我就是这样做的。我创建了一个名为WebUserSession的类,它实现了一个名为IUserSession的接口。然后我在创建控制器实例时使用依赖注入将其注入控制器。我在我的接口上实现了一个名为GetCurrentUser的方法,它将返回一个User对象,然后我可以根据需要将其用于我的操作中,方法是将其传递给视图。

using System.Security.Principal;
using System.Web;

public interface IUserSession
{
    User GetCurrentUser();
}

public class WebUserSession : IUserSession
{
    public User GetCurrentUser()
    {
        IIdentity identity = HttpContext.Current.User.Identity;
        if (!identity.IsAuthenticated)
        {
            return null;
        }

        User currentUser = // logic to grab user by identity.Name;
        return currentUser;
    }
}

public class SomeController : Controller
{
    private readonly IUserSession _userSession;

    public SomeController(IUserSession userSession)
    {
        _userSession = userSession;
    }

    public ActionResult Index()
    {
        User user = _userSession.GetCurrentUser();
        return View(user);
    }
}

如您所见,您现在可以根据需要检索用户。当然,您可以更改GetCurrentUser方法,以便首先查看会话或其他一些方法(如果您愿意),这样您就不会一直访问数据库。