Domanda

Ho dei problemi con il mio codice di gestione dei cookie. Su ogni pagina guardo per vedere se un valore di chiave è stata impostata. Il mio problema è che guardando il cookie crea un cookie vuoto.

A livello locale, posso guardare il cookie e quindi impostare il valore della chiave e tutto è bene nel mondo. Ma quando mi muovo il mio codice al server di prova, tutto ciò comporta in modo diverso. Per uno, a livello locale, solo un cookie viene rilasciata (mostrato in strumenti di Chrome). Sul server, 2 biscotti sono emessi con il medesimo codice.

Ho scritto questo codice di circa 4 anni fa, ed è stato progettato per NET 2.0 quando il comportamento HttpCookie è stato modificato in modo che guardando il cookie ha creato un vuoto se non esistesse. In precedenza, in .Net 1.1 nulla è stato restituito. Ora mi chiedo qualcosa di fondamentale è stato cambiato tra 2.0 e 4.0.

Vorrei sottolineare che la mia macchina locale è Windows 7 e il server è un server di Windows 2003 - non che dovrebbe fare alcuna differenza. L'unica cosa da notare è che l'applicazione è in esecuzione in una directory virtuale sul server. che potrebbe svolgere un ruolo in questioni? Non ne sono sicuro. Ho provato a impostare il percorso del cookie al percorso della directory virtuale senza fortuna.

Il mio cookie ha diversi strati, tra cui uno strato di base per trattare direttamente con il cookie HTTP, un livello di crittografia che può essere attivata o disattivata per il debug, e quindi un livello di gestione. Ho intenzione di condividere il mio codice nella speranza che ho un madornale errore nella mia logica.

Voglio anche ricordare che sto usando il cookie FormsAuthentication per qualcos'altro. Questo cookie è per alcuni dati estranei, ma necessarie,.

Il mio strato di biscotto di base:

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);
    }
}

Il mio livello di crittografia (batterie non incluse)

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);
        }
    }
}

E, infine, il livello di gestione dei cookie che avvolge tutto.

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);
    }
}

C'è una configurazione personalizzata insieme a questo che aiuta a configurare il cookie (s). Ecco cosa che appare come:

    <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>

Ora, il mio codice simile a questa nel mio web app:

    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();
    }

io chiamo la proprietà prima di vedere se l'ID dell'utente è stata impostata. Questa chiamata è fatto su ogni pagina. Poi in un'altra pagina l'utente può autenticare e io impostare l'ID nel cookie. Funziona tutto a livello locale, ma se mi ha colpito la home page sul server (dove id fa la ricerca sul id) e quindi autenticarsi, il valore del cookie non è impostato. Rimane vuoto.

È stato utile?

Soluzione

Il problema è che non sta chiamando

cookie.AppendCookie();

nel accesso set per myid? Si sta chiamando nel metodo SetMyId.

Altri suggerimenti

Il cookie viene creato quando si controlla per esso sul HttpContext.Current.Response. Ho lavorato intorno a questo attaccando una copia del cookie in HttpContext.Current.Items quando ho impostato. Poi, quando ho bisogno di controllare se è stato impostato o no, io Spunta i prodotti invece di Response.Cookies.

Non è la soluzione più elegante, ma ottiene il lavoro fatto.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top