MVC 身份 2 使用 FormsAuthenticationTicket
MVC Identity 2 using FormsAuthenticationTicket
我正在用自定义版本替换 (HttpContext.Current.User) IPrincipal,这样我就可以存储更多信息登录和用户。我在使用 FormsAuthtenticationTicket 之前已经这样做了,但是那些其他方法是基于 Memberhipship 和 SimpleMembership 提供者。
我的问题是,我可以使用 FormsAuthenticationTicket 来存储我的 ICustomPrincipal 的 cookie,因为它会干扰或破坏 OWIN 身份管道吗?我觉得我会混合苹果和橘子。
示例保存:
var user = userRepository.Users.Where(u => u.Email == viewModel.Email).First();
CustomPrincipalSerializeModel serializeModel = new CustomPrincipalSerializeModel();
serializeModel.UserId = user.Id;
serializeModel.FirstName = user.FirstName;
serializeModel.LastName = user.LastName;
JavaScriptSerializer serializer = new JavaScriptSerializer();
string userData = serializer.Serialize(serializeModel);
FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(
1,
viewModel.Email,
DateTime.Now,
DateTime.Now.AddMinutes(15),
false,
userData);
string encTicket = FormsAuthentication.Encrypt(authTicket);
HttpCookie faCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket);
Response.Cookies.Add(faCookie);
示例检索:
protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
{
HttpCookie authCookie = Request.Cookies[FormsAuthentication.FormsCookieName];
if (authCookie != null)
{
FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
JavaScriptSerializer serializer = new JavaScriptSerializer();
CustomPrincipalSerializeModel serializeModel = serializer.Deserialize<CustomPrincipalSerializeModel>(authTicket.UserData);
CustomPrincipal newUser = new CustomPrincipal(authTicket.Name);
newUser.UserId = serializeModel.UserId;
newUser.FirstName = serializeModel.FirstName;
newUser.LastName = serializeModel.LastName;
HttpContext.Current.User = newUser;
}
}
编辑
我有这个用于创建声明
public ClaimsIdentity CreateIdentity(
LoginAttempt loginAttempt)
{
UserProfile userProfile = GetUserProfile(loginAttempt.UserName);
var applicationUser = FindById(userProfile.AspNetUserId);
ClaimsIdentity identity;
try
{
identity = UserManager.CreateIdentity(applicationUser, DefaultAuthenticationTypes.ApplicationCookie);
}
catch (Exception ex)
{
_log.Error(ex.Message, ex);
return null;
}
//UserManager.GetClaims()
identity.AddClaim(new Claim("LoginAttemptId", loginAttempt.LoginAttemptId.ToString(),ClaimValueTypes.String));
identity.AddClaim(new Claim("UserProfileId", loginAttempt.UserProfileId.ToString(), ClaimValueTypes.String));
identity.AddClaim(new Claim("SubscriptionType", userProfile.SubscriptionType, ClaimValueTypes.String));
IList<string> roles= UserManager.GetRoles(applicationUser.Id);
identity.AddClaim(new Claim(ClaimTypes.Role, roles.First()));
return identity;
}
这用于提取
public static long GetLoginAttemptId(this IIdentity principal)
{
var claimsPrincipal = principal as ClaimsIdentity;
if (claimsPrincipal == null)
{
//throw new Exception("User is not logged in!");
return -1;
}
var nameClaim = claimsPrincipal.Claims.FirstOrDefault(c => c.Type == "LoginAttemptId");
if (nameClaim != null)
{
return Convert.ToInt64( nameClaim.Value);// as long;
}
return -1;
}
编辑
这些是我得到的索赔。我已经注销并重新登录。
有完全相同目的的声明。只有 new API 实际上是这样设计的。
声明基本上是一个 Dictionary<String, String>
,存储在 auth-cookie 中,可通过 IPrincipal
访问。但是你不需要做 ICustomPrincipal
因为你在 IPrincipal
后面得到的实际对象是 ClaimsPrincipal
并且有一个声明列表。
您需要在登录之前向 Idnentity 对象添加额外信息:
public async override Task CreateIdentityAsync(ApplicationUser applicationUser)
{
var identity = await base.CreateIdentityAsync(applicationUser, DefaultAuthenticationTypes.ApplicationCookie);
identity.AddClaim(new Claim("MyApp:FullName", applicationUser.FullName));
return identity;
}
然后您就可以通过扩展从 IPrincipal 中获取这些数据:
public static String GetFullName(this IPrincipal principal)
{
var claimsPrincipal = principal as ClaimsPrincipal;
if (claimsPrincipal == null)
{
throw new Exception("User is not logged in!");
}
var nameClaim = principal.Claims.FirstOrDefault(c => c.Type == "MyApp:FullName");
if (nameClaim != null)
{
return nameClaim.Value;
}
return String.Empty;
}
我已经在几个项目中成功地使用了这个方法。有关更多代码示例,请参阅 other similar answers。
这里是 another article,虽然我不鼓励在 MVC 应用程序中使用 Thread.CurrentPrincipal
或 ClaimsPrincipal.Current
- 你并不总是得到你期望的,特别是当用户未登录或处于早期阶段时AppPool 启动。
这种方法对我有用(使用 MVC4),与上面略有不同。
public class ApplicationUser : IdentityUser
{
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
userIdentity.AddClaim(new Claim("MyApp:OrganizationId", OrganizationID.ToString()));
return userIdentity;
}
public int OrganizationID { get; set; }
}
扩展方法。请注意,您应该使用 claimsPrincipal 变量(而不是主体变量)来获取声明。我认为在@trailmax 的出色回答中这是一个小错误(很抱歉没有在您的回答中对此发表评论,我的声誉不允许我这样做)。另外,我使用 IIdentity 而不是 IPrincipal
public static class IdentityExtensions
{
public static int GetOrganizationId(this IIdentity principal)
{
var claimsPrincipal = principal as ClaimsIdentity;
if (claimsPrincipal == null)
{
throw new Exception("User is not logged in!");
}
var nameClaim = claimsPrincipal.Claims.FirstOrDefault(c => c.Type == "MyApp:OrganizationId");
if (nameClaim != null)
{
return int.Parse(nameClaim.Value);
}
throw new Exception("ID doesn't exists");
}
}
然后,我像这样在控制器中使用扩展方法:
var organizationId = User.Identity.GetOrganizationId();
希望这对某人有用。
我正在用自定义版本替换 (HttpContext.Current.User) IPrincipal,这样我就可以存储更多信息登录和用户。我在使用 FormsAuthtenticationTicket 之前已经这样做了,但是那些其他方法是基于 Memberhipship 和 SimpleMembership 提供者。
我的问题是,我可以使用 FormsAuthenticationTicket 来存储我的 ICustomPrincipal 的 cookie,因为它会干扰或破坏 OWIN 身份管道吗?我觉得我会混合苹果和橘子。
示例保存:
var user = userRepository.Users.Where(u => u.Email == viewModel.Email).First();
CustomPrincipalSerializeModel serializeModel = new CustomPrincipalSerializeModel();
serializeModel.UserId = user.Id;
serializeModel.FirstName = user.FirstName;
serializeModel.LastName = user.LastName;
JavaScriptSerializer serializer = new JavaScriptSerializer();
string userData = serializer.Serialize(serializeModel);
FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(
1,
viewModel.Email,
DateTime.Now,
DateTime.Now.AddMinutes(15),
false,
userData);
string encTicket = FormsAuthentication.Encrypt(authTicket);
HttpCookie faCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket);
Response.Cookies.Add(faCookie);
示例检索:
protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
{
HttpCookie authCookie = Request.Cookies[FormsAuthentication.FormsCookieName];
if (authCookie != null)
{
FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
JavaScriptSerializer serializer = new JavaScriptSerializer();
CustomPrincipalSerializeModel serializeModel = serializer.Deserialize<CustomPrincipalSerializeModel>(authTicket.UserData);
CustomPrincipal newUser = new CustomPrincipal(authTicket.Name);
newUser.UserId = serializeModel.UserId;
newUser.FirstName = serializeModel.FirstName;
newUser.LastName = serializeModel.LastName;
HttpContext.Current.User = newUser;
}
}
编辑 我有这个用于创建声明
public ClaimsIdentity CreateIdentity(
LoginAttempt loginAttempt)
{
UserProfile userProfile = GetUserProfile(loginAttempt.UserName);
var applicationUser = FindById(userProfile.AspNetUserId);
ClaimsIdentity identity;
try
{
identity = UserManager.CreateIdentity(applicationUser, DefaultAuthenticationTypes.ApplicationCookie);
}
catch (Exception ex)
{
_log.Error(ex.Message, ex);
return null;
}
//UserManager.GetClaims()
identity.AddClaim(new Claim("LoginAttemptId", loginAttempt.LoginAttemptId.ToString(),ClaimValueTypes.String));
identity.AddClaim(new Claim("UserProfileId", loginAttempt.UserProfileId.ToString(), ClaimValueTypes.String));
identity.AddClaim(new Claim("SubscriptionType", userProfile.SubscriptionType, ClaimValueTypes.String));
IList<string> roles= UserManager.GetRoles(applicationUser.Id);
identity.AddClaim(new Claim(ClaimTypes.Role, roles.First()));
return identity;
}
这用于提取
public static long GetLoginAttemptId(this IIdentity principal)
{
var claimsPrincipal = principal as ClaimsIdentity;
if (claimsPrincipal == null)
{
//throw new Exception("User is not logged in!");
return -1;
}
var nameClaim = claimsPrincipal.Claims.FirstOrDefault(c => c.Type == "LoginAttemptId");
if (nameClaim != null)
{
return Convert.ToInt64( nameClaim.Value);// as long;
}
return -1;
}
编辑
这些是我得到的索赔。我已经注销并重新登录。
有完全相同目的的声明。只有 new API 实际上是这样设计的。
声明基本上是一个 Dictionary<String, String>
,存储在 auth-cookie 中,可通过 IPrincipal
访问。但是你不需要做 ICustomPrincipal
因为你在 IPrincipal
后面得到的实际对象是 ClaimsPrincipal
并且有一个声明列表。
您需要在登录之前向 Idnentity 对象添加额外信息:
public async override Task CreateIdentityAsync(ApplicationUser applicationUser)
{
var identity = await base.CreateIdentityAsync(applicationUser, DefaultAuthenticationTypes.ApplicationCookie);
identity.AddClaim(new Claim("MyApp:FullName", applicationUser.FullName));
return identity;
}
然后您就可以通过扩展从 IPrincipal 中获取这些数据:
public static String GetFullName(this IPrincipal principal)
{
var claimsPrincipal = principal as ClaimsPrincipal;
if (claimsPrincipal == null)
{
throw new Exception("User is not logged in!");
}
var nameClaim = principal.Claims.FirstOrDefault(c => c.Type == "MyApp:FullName");
if (nameClaim != null)
{
return nameClaim.Value;
}
return String.Empty;
}
我已经在几个项目中成功地使用了这个方法。有关更多代码示例,请参阅 other similar answers。
这里是 another article,虽然我不鼓励在 MVC 应用程序中使用 Thread.CurrentPrincipal
或 ClaimsPrincipal.Current
- 你并不总是得到你期望的,特别是当用户未登录或处于早期阶段时AppPool 启动。
这种方法对我有用(使用 MVC4),与上面略有不同。
public class ApplicationUser : IdentityUser
{
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
userIdentity.AddClaim(new Claim("MyApp:OrganizationId", OrganizationID.ToString()));
return userIdentity;
}
public int OrganizationID { get; set; }
}
扩展方法。请注意,您应该使用 claimsPrincipal 变量(而不是主体变量)来获取声明。我认为在@trailmax 的出色回答中这是一个小错误(很抱歉没有在您的回答中对此发表评论,我的声誉不允许我这样做)。另外,我使用 IIdentity 而不是 IPrincipal
public static class IdentityExtensions
{
public static int GetOrganizationId(this IIdentity principal)
{
var claimsPrincipal = principal as ClaimsIdentity;
if (claimsPrincipal == null)
{
throw new Exception("User is not logged in!");
}
var nameClaim = claimsPrincipal.Claims.FirstOrDefault(c => c.Type == "MyApp:OrganizationId");
if (nameClaim != null)
{
return int.Parse(nameClaim.Value);
}
throw new Exception("ID doesn't exists");
}
}
然后,我像这样在控制器中使用扩展方法:
var organizationId = User.Identity.GetOrganizationId();
希望这对某人有用。