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.CurrentPrincipalClaimsPrincipal.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();

希望这对某人有用。