从 HttpContext 获取自定义 IPrincipal 时无效的强制转换



在研究了几天的FormsAuthentication之后,我决定在FormsAuth cookie的UserData属性中存储一个序列化对象,并为HttpContext.Current.User使用自定义IPrincipal对象。

我找到的大多数指南都说将 IPrincipal 对象强制转换为您的对象。不过,我每次都收到无效的转换异常。我做错了什么?

我的用户数据

public class MyUserData
{
    public long UserId { get; set; }
    public string Username { get; set; }
    public bool IsSuperUser { get; set; }
    public string UnitCode { get; set; }
    public string EmailAddress { get; set; }
    public List<string> Roles { get; set; }
    // Serialize    
    public override string ToString()
    {
        JavaScriptSerializer serializer = new JavaScriptSerializer();
        string result = serializer.Serialize(this);
        return result;
    }
    // Deserialize
    public static MyUserData FromString(string text)
    {
        JavaScriptSerializer serializer = new JavaScriptSerializer();
        return serializer.Deserialize<MyUserData>(text);
    }
}

定制平台校长

public class MyCustomPrincipal : IPrincipal
{
    public MyUserData MyUserData { get; set; }
    public IIdentity Identity { get; private set; }
    public MyCustomPrincipal(MyUserData myUserData)
    {
        MyUserData = myUserData;
        Identity = new GenericIdentity(myUserData.Username);
    }
    public bool IsInRole(string role)
    {
        return MyUserData.Roles.Contains(role);
    }
}

全球.asax.cs

protected void Application_AuthenticateRequest(Object sender, EventArgs e)
    {
        HttpCookie authCookie = Context.Request.Cookies[FormsAuthentication.FormsCookieName];
        if (authCookie == null || authCookie.Value == "")
        {
            return;
        }
        FormsAuthenticationTicket authTicket;
        try
        {
            authTicket = FormsAuthentication.Decrypt(authCookie.Value);
        }
        catch
        {
            return;
        }
        if (Context.User != null)
        {
            // the from string deserializes the data
            MyUserData myUserData = MyUserData.FromString(authTicket.UserData);
            Context.User = new MyCustomPrincipal(myUserData);
        }
    }

我的页面

var myUserData = ((MyCustomPrincipal)(HttpContext.Current.User)).MyUserData;
// invalid cast exception (can't cast IPrincipal to MyCustomPrincipal)

第一条如下: http://primaryobjects.com/CMS/Article147.aspx

因此,似乎我获取数据的唯一方法是解密身份验证cookie,然后反序列化authCookie的userData字符串。

有什么建议吗?

更新

尝试遵循有关此SO问题的建议:在MVC中实现自定义标识和IPrincipal

代码在下面,但它不起作用。

[Serializable]
public class MyCustomPrincipal : IPrincipal, ISerializable
{
    public CustomUserData CustomUserData { get; set; }
    public IIdentity Identity { get; private set; }
    //public MyCustomPrincipal (IIdentity identity) { Identity = identity; }
    public MyCustomPrincipal(CustomUserData customUserData)
    {
        CustomUserData = customUserData;
        Identity = new GenericIdentity(customUserData.Username);
    }
    public bool IsInRole(string role)
    {
        return PlatformUserData.Roles.Contains(role);
    }

    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        if (context.State == StreamingContextStates.CrossAppDomain)
        {
            MyCustomPrincipal principal = new MyCustomPrincipal (this.CustomUserData );
            info.SetType(principal.GetType());
            System.Reflection.MemberInfo[] serializableMembers;
            object[] serializableValues;
            serializableMembers = FormatterServices.GetSerializableMembers(principal.GetType());
            serializableValues = FormatterServices.GetObjectData(principal, serializableMembers);
            for (int i = 0; i < serializableMembers.Length; i++)
            {
                info.AddValue(serializableMembers[i].Name, serializableValues[i]);
            }
        }
        else
        {
            throw new InvalidOperationException("Serialization not supported");
        }
    }
}

您是否在调试模式下运行?您可以在 HttpContext.Current.User 上放置断点,您将看到用户当时的类型。从您的Application_AuthenticateRequest方法来看,不能保证用户是您预期的类型。在达到自定义类型设置之前,有许多退出点。甚至这个代码:Context.User != null。你的期望是错误的。我还没有详细介绍Context.User,但是,就您的上下文而言,您期望Context.User是您的自定义用户。所以有效的检查应该是:

var custom = Context.Current as MyCustomPrinciple;
if(custom == null)
{
// Your construct code here.
}

我强烈建议:您需要进入调试模式,才能确切地查看发生了什么。

最新更新