好的,所以这似乎是一个普遍的需求。一个小小的谷歌搜索找到了很多方法来做到这一点。我对最“mvc正确”的方式感兴趣。
我的应用程序的右上角有一个问候Hello FirstName LastName
。现在,通过IPrincipal
(又名User.Identity.Name
)很容易获得登录用户的用户名。但是,这不会给我用户的名字和姓氏。我必须点击Membership API才能获得它。
点击Membership API有其缺点。它每次都会访问数据库,这会为每个提供的页面添加额外的数据库访问权限。在登录时设置一些会话变量很容易,但这仅适用于该会话。如果用户单击“记住我”,则下次不会进行登录,我仍然需要加载这些值。
Application_AuthenticateRequest
并点击成员资格api并将值存储在会话变量或类似内容中。这没关系,但似乎有点蛮力。有没有我没想过的方法?什么是最“mvc正确”的做法?
答案 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)
我将实现并扩展IPrincipal
和IIdentity
,因此当您访问User.Identity
时,您会找到LastName和FirstName。
这种方式更好imo。
对于我的项目,我已经扩展了IIdentity和IPrincipal,我的类添加了我总是需要“待在那里”的属性。对我而言,这不是一件大事,我的意思是,只有很多方法需要实施。
对于IIdentity,接口要求仅为AuthenticationType (string)
,IsAuthenticated (bool)
和Name (string)
。
在IPrincipal Identity (IIDentity)
和IsInRole (boolean)