【问题标题】:Unable to retrieve UserData on Forms authentication ticket无法检索 Forms 身份验证票证上的 UserData
【发布时间】:2015-01-11 15:48:40
【问题描述】:

我试图通过在我的控制器中运行以下代码从我的身份验证票中获取一些自定义字段值 -

[HttpPost]
    public ActionResult Add(AddCustomerModel customer)
    {
        customer.DateCreated = DateTime.Now;
        customer.CreatedBy = ((CustomPrincipal)(HttpContext.User)).Id;
        customer.LastUpdated = DateTime.Now;
        customer.LastUpdateBy = ((CustomPrincipal)(HttpContext.User)).Id;

        if (ModelState.IsValid)
        {
            _customerService.AddCustomer(customer);

            return RedirectToAction("Index");
        }

        return View(customer);
    }

当我尝试为新客户设置 CreatedBy 字段时,我收到以下错误 -

无法将“System.Security.Principal.GenericPrincipal”类型的对象转换为“GMS.Core.Models.CustomPrincipal”类型。

FormsAuthenticationTicket 中的我的 userData 字段设置为 JSON 字符串,其中包含两个字段 - Id 和 FullName。

这是我在控制器上的登录方法 -

    [HttpPost]
    [AllowAnonymous]
    public ActionResult Login(LoginModel model, string returnUrl)
    {
        if (Membership.ValidateUser(model.EmailAddress, model.Password))
        {
            LoginModel user = _userService.GetUserByEmail(model.EmailAddress);

            CustomPrincipalSerializeModel serializeModel = new CustomPrincipalSerializeModel();
            serializeModel.Id = user.ID;
            serializeModel.FullName = user.EmailAddress;
            //serializeModel.MergedRights = user.MergedRights;

            JavaScriptSerializer serializer = new JavaScriptSerializer();

            string userData = serializer.Serialize(serializeModel);

            FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(
             1,
             user.EmailAddress,
             DateTime.Now,
             DateTime.Now.AddHours(12),
             false,
             userData);

            string encTicket = FormsAuthentication.Encrypt(authTicket);
            HttpCookie faCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket);
            Response.Cookies.Add(faCookie);

            return RedirectToAction("Index", "Dashboard");
        }

        return RedirectToAction("Index");
    }

任何想法我哪里出错了?

【问题讨论】:

  • 您在Global.asax 中是否有一个protected void Application_PostAuthenticateRequest(object sender, EventArgs e) 方法,您可以在其中创建CustomPrincipal 并将其分配给HttpContext.Current.User

标签: asp.net-mvc asp.net-mvc-4 authentication


【解决方案1】:

要从 cookie 中检索用户数据,您可以使用以下代码

FormsIdentity formsIdentity = HttpContext.Current.User.Identity as FormsIdentity;
FormsAuthenticationTicket ticket = formsIdentity.Ticket;
string userData = ticket.UserData;

【讨论】:

    【解决方案2】:

    您需要创建 AuthenticationFilter 来将您的 GenericPrincipal 更改为您的 CustomPrincipal

    public class FormAuthenticationFilter : ActionFilterAttribute, IAuthenticationFilter
    {
        private readonly IResolver<HttpContextWrapper> httpContextWrapper;
    
        private readonly IResolver<ISecurityProvider> securityProviderResolver;
    
        public FormAuthenticationFilter(IResolver<HttpContextWrapper> httpContextWrapper, IResolver<ISecurityProvider> securityProviderResolver)
        {
            this.httpContextWrapper = httpContextWrapper;
            this.securityProviderResolver = securityProviderResolver;
        }
    
        public void OnAuthentication(AuthenticationContext filterContext)
        {
            if (filterContext.Principal != null && !filterContext.IsChildAction)
            {
                if (filterContext.Principal.Identity.IsAuthenticated &&
                    filterContext.Principal.Identity.AuthenticationType.Equals("Forms", StringComparison.InvariantCultureIgnoreCase))
                {
                    // Replace form authenticate identity
                    var formIdentity = filterContext.Principal.Identity as FormsIdentity;
                    if (formIdentity != null)
                    {
                        var securityProvider = this.securityProviderResolver.Resolve();
                        var principal = securityProvider.GetPrincipal(filterContext.Principal.Identity.Name, formIdentity.Ticket.UserData);
                        if (principal != null)
                        {
                            filterContext.Principal = principal;
                            this.httpContextWrapper.Resolve().User = principal;
                        }
                    }
                }
            }
        }
    
        public void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext)
        {
        }
    }
    

    然后将该过滤器注册到 GlobalFilter

    GlobalFilters.Filters.Add(new FormAuthenticationFilter());
    

    我代码中的 HttpContextWrapper 只是 HttpContext.Current 的包装器。您可以将其更改为您需要的任何内容。而 IAuthenticationFilter 只存在于 MVC 5 中。

    【讨论】:

    • 由于问题被明确标记为 mvc-4,如果它仅适用于 mvc-5,这有什么帮助?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-16
    • 2017-12-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多