HttpCookie работает локально, но не на сервере - PullRequest
0 голосов
/ 11 ноября 2010

У меня проблемы с кодом управления файлами cookie.На каждой странице я смотрю, было ли установлено значение ключа.Моя проблема в том, что при просмотре файла cookie создается пустой файл cookie.

Локально, я могу посмотреть файл cookie, а затем установить значение ключа, и все в порядке с миром.Но когда я перемещаю свой код на тестовый сервер, все ведет себя по-другому.Для одного локально выдается только один файл cookie (отображается в инструментах Chrome).На сервере 2 cookie-файла выдаются с одним и тем же кодом.

Я написал этот код около 4 лет назад, и он был разработан для .net 2.0, когда поведение HttpCookie было изменено так, что при просмотре cookie-файла создаетсяпустой, если его не было.Ранее в .Net 1.1 был возвращен ноль.Теперь мне интересно, что было изменено что-то фундаментальное между 2.0 и 4.0.

Я должен отметить, что мой локальный компьютер - Windows 7, а сервер - сервер Windows 2003 - не то, чтобы это имело значение.Единственное, что следует отметить, это то, что приложение работает в виртуальном каталоге на сервере.Может ли это играть роль в проблемах?Я не уверен.Я безуспешно пытался установить путь к файлу cookie для пути к виртуальному каталогу.

Мой файл cookie имеет несколько уровней, включая базовый уровень для работы непосредственно с файлом cookie http, уровень шифрования, который можно включитьвключено или выключено для отладки, а затем уровень управления.Я собираюсь поделиться своим кодом в надежде, что в моей логике есть явная ошибка.

Я также хочу упомянуть, что я использую cookie FormsAuthentication для чего-то еще.Этот файл cookie предназначен для некоторых посторонних, но необходимых данных.

Мой базовый уровень файлов cookie:

public abstract class BaseCookie
{
    #region Private Variables
    private string cookieName;
    private int timeout = 30;
    private ExpirationMode expirationMode = ExpirationMode.SlidingExpiration;
    private string domain;
    private bool httpOnly = true;
    private string path = "/";
    private bool secure;
    private string cookieValue;
    #endregion

    #region Public Properties

    /// <summary>
    /// The name of the cookie as it appears in the request and response
    /// </summary>
    protected string CookieName
    {
        get { return cookieName; }
        set { cookieName = value; }
    }

    /// <summary>
    /// The expiration mode of the cookie (default SlidingExpiration)
    /// </summary>
    public ExpirationMode ExpirationMode
    {
        get { return expirationMode; }
    }

    /// <summary>
    /// The timeout in minutes (default 30)
    /// </summary>
    public int Timeout
    {
        get { return timeout; }
        set { timeout = value; }
    }

    /// <summary>
    /// The cookie domain (default String.Empty)
    /// </summary>
    public string Domain
    {
        get { return domain; }
        set { domain = value; }
    }

    /// <summary>
    /// Whether or not the cookie is http only (default true)
    /// </summary>
    public bool HttpOnly
    {
        get { return httpOnly; }
        set { httpOnly = value; }
    }

    /// <summary>
    /// The path of the cookie (default "/")
    /// </summary>
    public string Path
    {
        get { return path; }
        set { path = value; }
    }

    /// <summary>
    /// Whether or not the cookie supports https (default false)
    /// </summary>
    public bool Secure
    {
        get { return secure; }
        set { secure = value; }
    }

    /// <summary>
    /// The Value of the cookie (NOTE: this should only be used for setting the value when calling AppendNewCookie().
    /// This will not change the value of the cookie after initialization.  Use SetCookieValue and GetCookieValue after initialization.
    /// </summary>
    public string Value
    {
        get { return cookieValue; }
        set { cookieValue = value; }
    }

    /// <summary>
    /// The cookie in the Request
    /// </summary>
    private HttpCookie RequestCookie
    {
        get
        {
            return HttpContext.Current.Request.Cookies.Get(CookieName);
        }
    }

    /// <summary>
    /// The cookie in the Response
    /// </summary>
    private HttpCookie ResponseCookie
    {
        get
        {
            return HttpContext.Current.Response.Cookies.Get(CookieName);
        }
    }

    #endregion

    #region Constructors
    /// <summary>
    /// Constructor setting the name of the cookie with Sliding Expiration
    /// </summary>
    /// <param name="cookieName">the name of the cookie</param>
    public BaseCookie(string cookieName)
        : this(cookieName, ExpirationMode.SlidingExpiration)
    {

    }

    /// <summary>
    /// Constructor setting the name of the cookie and the expiration mode 
    /// </summary>
    /// <param name="cookieName">the name of the cookie</param>
    /// <param name="expirationMode">the Olympus.Cookies.ExpirationMode of the cookie</param>
    public BaseCookie(string cookieName, ExpirationMode expirationMode)
    {
        this.cookieName = cookieName;

        CookieConfig config = Configuration.CookieConfiguration.Cookies[cookieName];

        if (config != null)
        {
            Domain = config.Domain;
            HttpOnly = config.HttpOnly;
            Path = config.Path;
            Secure = config.Secure;
            Timeout = config.Timeout;
        }

        //EnsureCookie();
    }
    #endregion

    /// <summary>
    /// This method ensures that the cookie is not empty if it exists in either the request or response.
    /// Due to changes in the cookie model for 2.0, this step is VITAL to cookie management.
    /// </summary>
    protected void EnsureCookie()
    {
        //if the cookie doesn't exist in the response (hasn't been altered or set yet this postback)
        if (IsNull(ResponseCookie))
        {
            //if the cookie exists in the request
            if (!IsNull(RequestCookie))
            {
                //get the cookie from the request
                HttpCookie cookie = RequestCookie;

                //update the expiration
                if (ExpirationMode == ExpirationMode.NoExpiration)
                {
                    cookie.Expires = DateTime.Now.AddYears(10);
                }
                else
                {
                    cookie.Expires = DateTime.Now.AddMinutes(Timeout);
                }

                //set the cookie into the response
                HttpContext.Current.Response.Cookies.Set(cookie);
            }
            else
            {
                //if the response and request cookies are null, append a new cookie
                AppendNewCookie();
            }
        }
    }

    /// <summary>
    /// Append an empty cookie to the Response
    /// </summary>
    public virtual void AppendNewCookie()
    {
        HttpCookie cookie = new HttpCookie(CookieName);

        cookie.Domain = Domain;
        cookie.HttpOnly = HttpOnly;
        cookie.Path = Path;
        cookie.Secure = Secure;

        cookie.Value = Value;

        if (ExpirationMode == ExpirationMode.NoExpiration)
        {
            cookie.Expires = DateTime.Now.AddYears(10);
        }
        else
        {
            cookie.Expires = DateTime.Now.AddMinutes(Timeout);
        }

        HttpContext.Current.Response.Cookies.Add(cookie);
    }

    /// <summary>
    /// Determine if the Cookie is null.
    /// </summary>
    /// <remarks>
    /// Due to changes in the 2.0 cookie model, looking in the request or respnse creates an empty cookie with an 
    /// expiration date of DateTime.MinValue.  Previously, a null value was returned.  This code calls one of these 
    /// empty cookies a null cookie.
    /// </remarks>
    /// <param name="cookie">the cookie to test</param>
    /// <returns>System.Boolean true if the cookie is "null"</returns>
    protected static bool IsNull(HttpCookie cookie)
    {
        if (cookie == null)
        {
            return true;
        }
        else
        {
            if (String.IsNullOrEmpty(cookie.Value) && cookie.Expires == DateTime.MinValue)
            {
                return true;
            }
        }

        return false;
    }

    /// <summary>
    /// Update the expiration of the response cookie
    /// <remarks>
    /// If this is not done, the cookie will never expire because it will be updated with an expiry of DateTime.Min
    /// </remarks>
    /// </summary>
    protected void SetExpiration()
    {
        if (ExpirationMode == ExpirationMode.NoExpiration)
        {
            ResponseCookie.Expires = DateTime.Now.AddYears(10);
        }
        else
        {
            ResponseCookie.Expires = DateTime.Now.AddMinutes(Timeout);
        }
    }

    /// <summary>
    /// Set the value of a cookie.
    /// </summary>
    /// <remarks>
    /// Setting value will override all attributes.
    /// </remarks>
    /// <param name="value">the value to set the cookie</param>
    public virtual void SetCookieValue(string value)
    {
        //EnsureCookie();

        ResponseCookie.Value = value;

        SetExpiration();
    }

    /// <summary>
    /// Get the default value (the first value) of the cookie
    /// </summary>
    /// <remarks>
    /// Getting the value only returns the first value (values[0]) because it has no key.
    /// </remarks>
    /// <returns>System.String</returns>
    public virtual string GetCookieValue()
    {
        //EnsureCookie();

        string returnValue = "";

        if (RequestCookie.Values.Count > 0)
        {
            returnValue = RequestCookie.Values[0];
        }

        return returnValue;
    }

    /// <summary>
    /// Set a key/value pair
    /// </summary>
    /// <param name="key">the key for the pair</param>
    /// <param name="value">the value to assign to the key</param>
    public virtual void SetKeyValue(string key, string value)
    {
        //EnsureCookie();

        ResponseCookie.Values.Set(key, value);

        SetExpiration();
    }

    /// <summary>
    /// Get a value for a given key
    /// </summary>
    /// <param name="key">the key to find a value of</param>
    /// <returns>System.String</returns>
    public virtual string GetKeyValue(string key)
    {
        //EnsureCookie();

        return RequestCookie.Values[key];
    }

    /// <summary>
    /// Expire the cookie
    /// </summary>
    public virtual void Expire()
    {
        //Setting the expiration does not remove the cookie from the next request
        ResponseCookie.Expires = DateTime.Now.AddDays(-1);
    }
}

Мой уровень шифрования (батареи не включены)

internal sealed class EncryptedCookie : BaseCookie
{
    private string decryptedCookieName;

    new public string Value
    {
        get
        {
            if (Configuration.CookieConfiguration.Cookies[decryptedCookieName].EnableEncryption)
            {
                return Encryption.DecryptQueryString(base.Value);
            }
            else
            {
                return base.Value;
            }
        }
        set
        {
            if (Configuration.CookieConfiguration.Cookies[decryptedCookieName].EnableEncryption)
            {
                base.Value = Encryption.EncryptQueryString(value);
            }
            else
            {
                base.Value = value;
            }
        }
    }

    public EncryptedCookie(string cookieName)
        : base(cookieName)
    {
        decryptedCookieName = cookieName;

        if (Configuration.CookieConfiguration.Cookies[decryptedCookieName].EnableEncryption)
        {
            CookieName = Encryption.EncryptQueryString(cookieName);
        }

        EnsureCookie();
    }

    public EncryptedCookie(string cookieName, ExpirationMode expirationMode)
        : base(cookieName, expirationMode)
    {
        decryptedCookieName = cookieName;

        if (Configuration.CookieConfiguration.Cookies[decryptedCookieName].EnableEncryption)
        {
            CookieName = Encryption.EncryptQueryString(cookieName);
        }

        EnsureCookie();
    }

    public override string GetCookieValue()
    {
        if (Configuration.CookieConfiguration.Cookies[decryptedCookieName].EnableEncryption)
        {
            return Encryption.DecryptQueryString(base.GetCookieValue());
        }
        else
        {
            return base.GetCookieValue();
        }
    }

    public override void SetCookieValue(string value)
    {
        if (Configuration.CookieConfiguration.Cookies[decryptedCookieName].EnableEncryption)
        {
            base.SetCookieValue(Encryption.EncryptQueryString(value));
        }
        else
        {
            base.SetCookieValue(value);
        }
    }

    public override void SetKeyValue(string key, string value)
    {
        if (Configuration.CookieConfiguration.Cookies[decryptedCookieName].EnableEncryption)
        {
            base.SetKeyValue(Encryption.EncryptQueryString(key), Encryption.EncryptQueryString(value));
        }
        else
        {
            base.SetKeyValue(key, value);
        }
    }

    public override string GetKeyValue(string key)
    {
        if (Configuration.CookieConfiguration.Cookies[decryptedCookieName].EnableEncryption)
        {
            return Encryption.DecryptQueryString(base.GetKeyValue(Encryption.EncryptQueryString(key)));
        }
        else
        {
            return base.GetKeyValue(key);
        }
    }
}

Инаконец, слой управления файлами cookie, который оборачивает все это.

public sealed class Cookie
{
    string cookieName;

    public Cookie(string cookieName)
    {
        this.cookieName = cookieName;
    }

    public void AppendCookie()
    {
        EncryptedCookie cookie = new EncryptedCookie(cookieName);

        cookie.AppendNewCookie();
    }

    public void SetAttribute(string attributeName, string attributeValue)
    {
        EncryptedCookie cookie = new EncryptedCookie(cookieName);

        cookie.SetKeyValue(attributeName, attributeValue);
    }

    public void SetValue(string value)
    {
        EncryptedCookie cookie = new EncryptedCookie(cookieName);

        cookie.SetCookieValue(value);
    }

    public string GetValue()
    {
        EncryptedCookie cookie = new EncryptedCookie(cookieName);

        return cookie.GetCookieValue();
    }

    public string GetAttribute(string attributeName)
    {
        EncryptedCookie cookie = new EncryptedCookie(cookieName);

        return cookie.GetKeyValue(attributeName);
    }
}

Кроме этого, существует настраиваемая конфигурация, которая помогает настроить файлы cookie.Вот как это выглядит:

    <cookie>
        <cookies>
            <!-- enableEncryption: [ true | false ] -->
            <!-- expirationMode: [ SlidingExpiration | NoExpiration ] -->
            <!-- timeout: the timeout in minutes (Default 30)-->
            <!-- httpOnly: [ true | false ] -->
            <!-- secure: [ true | false ] -->
            <add name="MyCookie" enableEncryption="true" expirationMode="SlidingExpiration" timeout="64800" domain="" httpOnly="true" path="" secure="false" />
        </cookies>
    </cookie>

Теперь мой код выглядит примерно так в моем веб-приложении:

    public int MyId
    {
        get
        {

            Cookie cookie = new Cookie(ConfigurationHelper.Cookies.MyCookie);

            int myId= 0;
            try
            {
                Int32.TryParse(cookie.GetAttribute(BILLERID_KEY), out myId);
            }
            catch (System.NullReferenceException)
            {
                //do nothing on purpose.
            }

            return myId;

        }
        set
        {
            Cookie cookie = new Cookie(ConfigurationHelper.Cookies.MyCookie);

            cookie.SetAttribute(MY_KEY, value.ToString());
        }
    }

    public void SetMyId(int myId)
    {
        Cookie cookie = new Cookie(ConfigurationHelper.Cookies.MyCookie);

        cookie.SetAttribute(MYID_KEY, myId.ToString());

        cookie.AppendCookie();
    }

Сначала я вызываю свойство, чтобы узнать, был ли идентификатор пользователязадавать.Этот звонок делается на каждой странице.Затем на другой странице пользователь может пройти аутентификацию, и я установил идентификатор в cookie.Все это работает локально, но если я попадаю на домашнюю страницу на сервере (где id выполняет поиск по id) и затем аутентифицируюсь, значение cookie не устанавливается.Он остается пустым.

Ответы [ 2 ]

1 голос
/ 11 ноября 2010

Это проблема, которую вы не вызываете

cookie.AppendCookie();

в наборе доступа для MyId? Вы вызываете его в методе SetMyId.

1 голос
/ 11 ноября 2010

Файл cookie создается при его проверке на HttpContext.Current.Response.Я работал над этим, прикрепляя копию cookie в HttpContext.Current.Items, когда я его установил.Затем, когда мне нужно проверить, был ли он установлен или нет, я выбираю Предметы вместо Response.Cookies.

Не самое элегантное решение, но оно выполняет свою работу.

...