如何初始化授权信息

时间:2011-09-02 05:25:35

标签: asp.net-mvc-3 authentication forms-authentication

好的,所以这似乎是一个普遍的需求。一个小小的谷歌搜索找到了很多方法来做到这一点。我对最“mvc正确”的方式感兴趣。

我的应用程序的右上角有一个问候Hello FirstName LastName。现在,通过IPrincipal(又名User.Identity.Name)很容易获得登录用户的用户名。但是,这不会给我用户的名字和姓氏。我必须点击Membership API才能获得它。

点击Membership API有其缺点。它每次都会访问数据库,这会为每个提供的页面添加额外的数据库访问权限。在登录时设置一些会话变量很容易,但这仅适用于该会话。如果用户单击“记住我”,则下次不会进行登录,我仍然需要加载这些值。

  1. 我可以创建自己的会员提供程序来进行一些缓存,但这或多或少都是为了单一目的而做的很多工作。
  2. 我可以使用Application_AuthenticateRequest并点击成员资格api并将值存储在会话变量或类似内容中。这没关系,但似乎有点蛮力。
  3. 我可以注册一个全局过滤器并处理OnAuthenticate,基本上做同样的事情。这似乎好一点,但我不知道这里的后果。
  4. 我可以派生一个基本控制器,并简单地添加属性来提供这些信息。这似乎有点“老派”,我讨厌为一个目的制作一个基类。
  5. 我可以创建一个缓存静态方法来获取有关首次访问的信息。这基本上不比单身人士好多了。
  6. 我也可以创建自己的IPrincipal,但这意味着每次都要使用它来获取数据,这看起来很笨拙。我可以将它包装在另一个类中以简化它,但仍然......
  7. 我可以将数据存储在表单身份验证cookie中,然后从那里获取。有一些工具可以使这更容易。
  8. 有没有我没想过的方法?什么是最“mvc正确”的做法?

3 个答案:

答案 0 :(得分:5)

我认为最好的方法是使用Cookie。以下是我在my project中使用的解决方案:

创建一个类来保存数据

[DataContract]
[Serializable()]
public class AuthData {

    [DataMember]
    public String UserName { get; set; }

    [DataMember]
    public String FirstName { get; set; }

    [DataMember]
    public String LastName { get; set; }

    [DataMember]
    public String Email { get; set; }

    // any other property you need to a light-store for each user

    public override string ToString() {
        string result = "";
        try {
            using (MemoryStream stream = new MemoryStream()) {
                BinaryFormatter formatter = new BinaryFormatter();
                formatter.Serialize(stream, this);
                result = Convert.ToBase64String(stream.ToArray());
            }
        } catch (Exception ex) {
            throw new HttpException(ex.Message);
        }
        return result;
    }

    static public AuthData FromString(String data) {
        AuthData result = null;
        try {
            byte[] array = Convert.FromBase64String(data);
            using (MemoryStream stream = new MemoryStream(array)) {
                stream.Seek(0, 0);
                BinaryFormatter formatter = new BinaryFormatter();
                result = (AuthData)formatter.Deserialize(stream, null);
            }
        } catch (Exception ex) {
            throw new HttpException(ex.Message);
        }
        return result;
    }
}

登录方式:

public static bool SignIn(string userName, string password, bool persistent){
    if (Membership.ValidateUser(userName, password)) {
        SetAuthCookie(userName, persistent);
        return true;
    }
    return false;
}

设置AuthCookie:

public static void SetAuthCookie(string userName, bool persistent) {
    AuthData data = GetAuthDataFromDB(); // implement this method to retrieve data from database as an AuthData object
    var ticket = new FormsAuthenticationTicket(
        1, 
        userName, 
        DateTime.Now,
        DateTime.Now.Add(FormsAuthentication.Timeout), 
        persistent, 
        data.ToString(), 
        FormsAuthentication.FormsCookiePath
        );
    string hash = FormsAuthentication.Encrypt(ticket);
    HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, hash);
    cookie.Expires = DateTime.Now.Add(FormsAuthentication.Timeout);
    cookie.HttpOnly = false;
    cookie.Path = FormsAuthentication.FormsCookiePath;
    HttpContext.Current.Response.Cookies.Add(cookie);
}

获取AuthCookie:

public static AuthData GetAuthCookie() {
    if (HttpContext.Current.User != null && HttpContext.Current.User.Identity.IsAuthenticated && HttpContext.Current.User.Identity is FormsIdentity) {
        FormsIdentity id = (FormsIdentity)HttpContext.Current.User.Identity;
        FormsAuthenticationTicket ticket = id.Ticket;
        var data = AuthData.FromString(ticket.UserData);
        HttpContext.Current.Items["AuthDataContext"] = data;
        return data;
    }
    return null;
}

在ControllerBase中:

private AuthData _authData;
private bool _authDataIsChecked;
public AuthData AuthData {
    get {
        _authData = System.Web.HttpContext.Current.Items["AuthDataContext"] as AuthData;
        if (!_authDataIsChecked && _authData == null) {
            SignService.GetAuthCookie();
            _authData = System.Web.HttpContext.Current.Items["AuthDataContext"] as AuthData;
            _authDataIsChecked = true;
        }
        return _authData;
    }
}

答案 1 :(得分:1)

FormsAuthenticationExtensions项目解决了在auth cookie本身中存储附加信息的问题。 http://formsauthext.codeplex.com/

这可以避免数据库命中,并且与auth cookie一样长,因此如果用户要求“记住我”,它就会起作用。它可以以与标准表单身份验证相同的方式(在MVC中)使用。

对于你的问题,最MVCisch的方式是什么:我首先要决定我想要保存信息的位置。问题的这一部分相当独立于MVC框架,因为概念(会话,发布数据,cookie等)有或没有给出。

答案 2 :(得分:1)

我将实现并扩展IPrincipalIIdentity,因此当您访问User.Identity时,您会找到LastName和FirstName。 这种方式更好imo。

对于我的项目,我已经扩展了IIdentity和IPrincipal,我的类添加了我总是需要“待在那里”的属性。对我而言,这不是一件大事,我的意思是,只有很多方法需要实施。

对于IIdentity,接口要求仅为AuthenticationType (string)IsAuthenticated (bool)Name (string)

在IPrincipal Identity (IIDentity)IsInRole (boolean)