【问题标题】:MVC Identity 2 using FormsAuthenticationTicket使用 FormsAuthenticationTicket 的 MVC 身份 2
【发布时间】:2015-03-24 02:14:41
【问题描述】:

我将 (HttpContext.Current.User) IPrincipal 替换为自定义版本,以便我可以存储更多信息登录和用户。我在使用 FormsAuthtenticationTicket 之前已经这样做了,但其他方法是基于 Membershipship 和 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;
        }

编辑 这些是我得到的主张。我已注销并重新登录。

【问题讨论】:

    标签: asp.net-mvc-5 forms-authentication asp.net-identity-2


    【解决方案1】:

    这种方法对我有用(使用 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; }
    }
    

    扩展方法。请注意,您应该使用 claimPrincipal 变量(而不是主要变量)来获取声明。我认为这是@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();
    

    希望这对某人有用。

    【讨论】:

      【解决方案2】:

      有些声明的目的完全相同。只有新的 API 实际上是这样设计的。

      声明基本上是一个Dictionary&lt;String, String&gt;,它存储在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;
      }
      

      我已经在一些项目中成功地使用了这种方法。有关更多代码示例,请参阅othersimilaranswers
      这里是another article,尽管我不鼓励在 MVC 应用程序中使用 Thread.CurrentPrincipalClaimsPrincipal.Current - 你并不总是得到你所期望的,尤其是当用户未登录或 AppPool 启动的早期阶段。

      【讨论】:

      • 我无法获得 wrk 的扩展名
      • 怎么样?有什么问题?
      • 对不起,我想通了。感谢您的回答。它完美地解决了
      • 当我添加了一个已知类型为“ClaimTypes.Role”的声明但当我添加了一个自定义字符串时,上述解决方案运行良好。 MyApp:loginAttemptId 它没有找到声明。
      • 小心预定义类型 - 它们可能被系统使用,您可能会干扰系统数据。所有用户角色都添加为 ClaimTypes.Role 类型的声明,如果您使用此声明添加更多信息,您将为该用户提供一个名为“Joe Bloggs”的角色。
      猜你喜欢
      • 1970-01-01
      • 2013-06-10
      • 1970-01-01
      • 1970-01-01
      • 2011-02-06
      • 1970-01-01
      • 2013-03-03
      • 2014-03-20
      • 1970-01-01
      相关资源
      最近更新 更多