IsAuthenticated является ложным!странное поведение + обзорный вопрос - PullRequest
2 голосов
/ 16 января 2011

Это функция входа в систему (после того, как я проверяю имя пользователя и пароль, я загружаю данные пользователя в переменную "user" и вызываю функцию входа в систему:

public static void Login(IUser user)
{
    HttpResponse Response = HttpContext.Current.Response;
    HttpRequest Request = HttpContext.Current.Request;

    FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1,
        user.UserId.ToString(), DateTime.Now, DateTime.Now.AddHours(12), false,
        UserResolver.Serialize(user));

    HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName,
        FormsAuthentication.Encrypt(ticket));
    cookie.Path = FormsAuthentication.FormsCookiePath;

    Response.Cookies.Add(cookie);

    string redirectUrl = user.HomePage;

    Response.Redirect(redirectUrl, true);
}

UserResolver - это следующий класс:

public class UserResolver
{
    public static IUser Current
    {
        get
        {
            IUser user = null;
            if (HttpContext.Current.User.Identity.IsAuthenticated)
            {
                FormsIdentity id = (FormsIdentity)HttpContext.Current.User.Identity;
                FormsAuthenticationTicket ticket = id.Ticket;
                user = Desrialize(ticket.UserData);
            }
            return user;
        }
    }

    public static string Serialize(IUser user)
    {
        StringBuilder data = new StringBuilder();
        StringWriter w = new StringWriter(data);
        string type = user.GetType().ToString();
        //w.Write(type.Length);
        w.WriteLine(user.GetType().ToString());
        StringBuilder userData = new StringBuilder();
        XmlSerializer serializer = new XmlSerializer(user.GetType());
        serializer.Serialize(new StringWriter(userData), user);
        w.Write(userData.ToString());
        w.Close();
        return data.ToString();
    }

    public static IUser Desrialize(string data)
    {
        StringReader r = new StringReader(data);
        string typeStr = r.ReadLine();
        Type type=Type.GetType(typeStr);
        string userData = r.ReadToEnd();
        XmlSerializer serializer = new XmlSerializer(type);
        return (IUser)serializer.Deserialize(new StringReader(userData));
    }
}

И global.asax реализует следующее:

void Application_PostAuthenticateRequest(Object sender, EventArgs e)
{
    IPrincipal p = HttpContext.Current.User;
    if (p.Identity.IsAuthenticated)
    {
        IUser user = UserResolver.Current;
        Role[] roles = user.GetUserRoles();
        HttpContext.Current.User = Thread.CurrentPrincipal =
            new GenericPrincipal(p.Identity, Role.ToString(roles));
    }
}

Первый вопрос: правильно ли я это делаю?

Второй вопрос - странная вещь! Пользовательская переменная, которую я передаюУ входа в систему 4 члена: UserName, Password, Name, Id. Когда UserResolver.Current был выполнен, я получил экземпляр пользователя. Я решил изменить структуру пользователя - я добавляю массив объектов Warehouse. С того времени, когда UserResolver.Current выполнялся(после входа в систему) HttpContext.Current.User.Identity.IsAuthenticated был ложным, и я не смог получить пользовательские данные. Когда я удалил хранилище [] из структуры пользователя, он снова начал работать нормально и HttpContext.Current.User.Identity.IsAuthenticated становится правдой после того, как я войду в систему.

В чем причина этого странного поведения?

Ответы [ 2 ]

3 голосов
/ 26 января 2011

Во-первых, вам не нужно делать HttpContext.Current из Global.asax.Global.asax происходит от HttpApplication.Так что все, что вам нужно сделать, это получить свойство Context.Это может помочь сделать этот код немного чище.

    //this is all you need in your global.asax
    void Application_PostAuthenticateRequest(Object sender, EventArgs e)
    {
        if(Context.User.Identity.IsAuthenticated)
        {
            var user = UserResolver.Current;
            Context.User = Thread.CurrentPrincipal = new UserWrapperPrincipal(user, Context.User.Identity);
        }
    }

    //this helper class separates the complexity
    public class UserWrapperPrincipal: IPrincipal, IUser
    {
        private readonly IUser _user;
        private readonly IIdentity _identity;

        public UserWrapperPrincipal(IUser user, IIdentity identity)
        {
            _user = user;
            _identity = identity;
        }

        private IList<string> RoleNames
        {
            get { return _user.GetUserRoles().Select(role => role.ToString()); }
        }

        public IIdentity Identity { get { return _identity; } }

        public bool IsInRole(string role) { return RoleNames.Contains(role); }

    }

Исходя из вашей ошибки, похоже, проблема в том, что ваша функция сериализации или функция десериализации повреждают данные.Тем не менее, проблемная область, вероятно, не эти функции.Либо существует проблема с сериализацией объекта Warehouse (сериализация сложных типов иногда бывает сложной), либо с сериализацией действительного массива.Поскольку вы используете .NET XmlSerializer по умолчанию, есть хорошая статья о настройке и управлении способом обработки различных объектов, доступная по адресу http://www.diranieh.com/NETSerialization/XMLSerialization.htm.

С другой стороны, вы уверены, что это лучший способ сохранить эти данные в вашем приложении?Хранение идентификатора пользователя и имени имеет смысл.Когда вы начинаете хранить в вашем файле cookie сериализованные массивы сложных объектов, это может указывать на то, что вы с самого начала не подходите к проблеме правильно.

1 голос
/ 16 января 2011

Я предполагаю, что ваш код находится в каком-либо событии входа в систему, и вы создаете пользовательскую форму авторизации.

Вам также необходимо затем создать объект User из файла cookie при каждом запросе страницы

public class AuthHttpModule : IHttpModule { 
    public virtual void Init(HttpApplication app) {
        app.AuthenticateRequest += new EventHandler(app_AuthenticateRequest);
    }
    private void app_AuthenticateRequest(object source, EventArgs e) {  
        HttpCookie cookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
        if (cookie == null) {
            HttpContext.Current.User = null;
        } else {
            cookie = HttpContext.Current.Response.Cookies[FormsAuthentication.FormsCookieName];
            FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(cookie.Value);
            HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(new FormsIdentity(ticket), new string[0]);
        }
        bool result = HttpContext.Current.Request.IsAuthenticated;
    }
}

РЕДАКТИРОВАТЬ

Попробуйте добавить это в свой глобальный

void Application_AuthenticateRequest(Object sender, EventArgs e)
    HttpCookie cookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
    if (cookie != null) {
        FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(cookie.Value);
        HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(new FormsIdentity(ticket), new string[0]);
    }
}
...