Неверное приведение при получении пользовательского IPrincipal из HttpContext
После изучения FormsAuthentication в течение нескольких дней я решил сохранить сериализованный объект в свойстве UserData куки-файла FormsAuth и использовать собственный объект IPrincipal для HttpContext.Current.User.
Большинство руководств, которые я нашел, говорят о приведении объекта IPrincipal к вашему объекту. Я каждый раз получаю недопустимое исключение приведения. Что я делаю неправильно?
MyUserData
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);
}
}
CustomPlatformPrincipal
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);
}
}
Global.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)
Статья I была следующая: http://primaryobjects.com/CMS/Article147.aspx
Так что, похоже, единственный способ получить мои данные - это расшифровать cookie-файл auth, а затем десериализовать строку userData authCookie.
Какие-либо предложения?
Обновить
Попробовал следующие предложения по этому вопросу SO: Реализация пользовательской идентификации и IPrincipal в MVC
Код ниже, но это не сработало.
[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");
}
}
}
1 ответ
Вы работали в режиме отладки? Вы можете поставить точку останова на 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.
}
Я настоятельно рекомендую: вам нужно перейти в режим отладки, чтобы точно увидеть, что происходит.