11

Ho attivato SQL-Server Reporting Services 2012 (SSRS 2012) per l'autenticazione dei moduli in modo da poterlo utilizzare su Internet.SSRS: Perché i cookie SKA si accumulano finché non si verifica "Richiesta non valida HTTP 400 - Richiesta troppo lunga"?

Non sono riuscito a trovare un esempio di autenticazione di moduli per SSRS 2012, quindi ho dovuto prendere uno SSRS 2008R2 e adattarlo per il 2012 per Single-Sign-On (SSO).

A quel punto tutto sembrava funzionare come previsto; Sono persino riuscito a far funzionare SSO tra i domini.

Ma ora ho un problema:

stavo testando tutti i rapporti (più di 200), con Google Chrome, perché ho dovuto inserire un po 'di JavaScript che altera td border-size per che i display HTML diritto a non IE5-QuirksMode. Dopo circa il rapporto 50 °, ho improvvisamente avuto:

"HTTP 400 Bad Request - Richiesta troppo lungo"

Dopo di che, non ho potuto vedere qualsiasi altro rapporto, nemmeno quelli che ha fatto il lavoro in precedenza.

Il problema sembra essere causato da troppi cookie, e infatti, quando ho eliminato alcuni cookie "* _SKA" (Session Keep Alive?), Ha iniziato a funzionare di nuovo.

SSRS Sucks

Il mio problema ora è che io non so che cosa provoca questo "troppo pieno cookie". Inoltre non so, se questo è un bug in Chrome, un bug in vaniglia SSRS o un bug causato dalla nuova autenticazione dei moduli.

Tutto ciò che faccio nelle nuove forme-di autenticazione che ha qualcosa a che fare con i biscotti è questo:

using System; 
using System.Collections.Generic; 
using System.Text; 


namespace FormsAuthentication_RS2012 
{ 


    internal class FormsAuthenticationWorkaround 
    { 

     public static void RedirectFromLoginPage(string strUser, bool createPersistentCookie) 
     { 
      //string url = System.Web.Security.FormsAuthentication.GetRedirectUrl(strUser, true); 
      string url = GetRedirectUrlWithoutFailingOnColon(strUser, createPersistentCookie); 
      SQL.Log("User: '" + strUser + "' ReturnUrl", url); 

      if (System.Web.HttpContext.Current != null && System.Web.HttpContext.Current.Response != null) 
       System.Web.HttpContext.Current.Response.Redirect(url); 
     } 


     // https://github.com/mono/mono/blob/master/mcs/class/System.Web/System.Web.Security/FormsAuthentication.cs 
     // @MSFT: WTF are u guys smoking ? 
     public static string GetRedirectUrlWithoutFailingOnColon(string userName, bool createPersistentCookie) 
     { 
      if (userName == null) 
       return null; 

      System.Web.Security.FormsAuthentication.SetAuthCookie(userName, true, "/"); 

      string returnUrl = null; 

      if (System.Web.HttpContext.Current != null && System.Web.HttpContext.Current.Request != null) 
       returnUrl = System.Web.HttpContext.Current.Request.QueryString["ReturnUrl"]; 

      if (returnUrl != null) 
       return returnUrl; 

      returnUrl = System.Web.Security.FormsAuthentication.DefaultUrl; 
      return returnUrl; 
     } 


    } 


} 

E come questo codice crea la "sqlAuthCookie" che si vede in fondo. C'è solo un "sqlAuthCookie" quindi non penso che questo possa essere un bug di autenticazione dei moduli.

Il problema sembra essere i cookie SKA, che AFAIK non ha nulla a che fare con l'autenticazione di moduli e tutto ciò che ha a che fare con Vanilla SSRS.

L'unica altra cosa che ho potuto vedere come una ragione per questo è la modifica del timeout del cookie di autenticazione di moduli a 720 minuti che ho inserito nella sezione di autenticazione dei moduli nel file web.config.

<authentication mode="Forms"> 
    <forms loginUrl="logon.aspx" name="sqlAuthCookie" timeout="720" path="/"> 
    </forms> 
    </authentication> 

Qualcuno sa cosa posso fare per evitare di essere sommerso dalla sessione keep-alive biscotti (tranne che per l'eliminazione di quei biscotti manualmente)?

Non è un problema per me di per sé, a parte essendo altamente fastidioso, ma che sta per essere un problema perché gli utenti probabilmente non saranno molto comprensione di quel ...

risposta

8

Problema indicato come fisso in SQL Server 2012 SP1 CU7. (vedere i commenti di Microsoft nel connect issue)
Ma ancora presente in SQL Server 2014.


La sezione successiva si applica, se non è possibile installare SQL Server 2012 SP1 CU7:

OK, ha ottenuto la risposta me stesso.

Il cookie keep-alive viene emesso ogni volta che si apre un report.
Ora, questo diventa un problema quando si apre (o si aggiorna o si passa ad un'altra pagina), ad esempio, più di 110 - 120 rapporti, senza chiudere il browser.

Quindi salvaguardiamo eliminando i cookie in eccesso e impostando un limite di sicurezza su appx. 1/2 del massimo previsto di 120 cookie.

I cookie sono HttpOnly e scadono quando si chiude il browser (cookie di sessione).
Sono cookie HttpSole non protetti, motivo per cui non sono riuscito nel mio tentativo di eliminarli tramite JavaScript.
Quindi diventa necessario eliminarli dal lato server. Dato che non possiamo modificare ReportServer, dobbiamo usare lo scripting inline.

<body style="margin: 0px; overflow: auto"> 


<script type="text/C#" runat="server"> 
protected string ClearSessionKeepAliveCookiesToPreventHttp400HeaderTooLong() 
{ 
    if(Request == null || Request.Cookies == null) 
     return ""; 

    if(Request.Cookies.Count < 60) 
     return ""; 

    // System.Web.HttpContext.Current.Response.Write("<h1>"+Request.Cookies.Count.ToString()+"</h1>"); 
    for(int i = 0; i < Request.Cookies.Count; ++i) 
    { 
     if(StringComparer.OrdinalIgnoreCase.Equals(Request.Cookies[i].Name, System.Web.Security.FormsAuthentication.FormsCookieName)) 
      continue; 

     if(!Request.Cookies[i].Name.EndsWith("_SKA", System.StringComparison.OrdinalIgnoreCase)) 
      continue; 

     if(i > 60) 
      break; 

     //System.Web.HttpContext.Current.Response.Write("<h1>"+Request.Cookies[i].Name+"</h1>"); 

     System.Web.HttpCookie c = new System.Web.HttpCookie(Request.Cookies[i].Name); 
     //c.Expires = System.DateTime.Now.AddDays(-1); 
     c.Expires = new System.DateTime(1970, 1 ,1); 
     c.Path = Request.ApplicationPath + "/Pages"; 
     c.Secure = false; 
     c.HttpOnly = true; 

     // http://stackoverflow.com/questions/5517273/httpcookiecollection-add-vs-httpcookiecollection-set-does-the-request-cookies 
     //Response.Cookies[Request.Cookies[i].Name] = c; 
     //Response.Cookies.Add(c); 
     Response.Cookies.Set(c); 
    } 

    return ""; 
} 


</script> 

<%=ClearSessionKeepAliveCookiesToPreventHttp400HeaderTooLong()%> 

    <form style="width:100%;height:100%" runat="server" ID="ReportViewerForm"> 
+0

Chiudere il browser non ha funzionato con Chrome. Ho dovuto cancellare manualmente i cookie. Proverò presto la tua soluzione lato server. Grazie! – kravits88

+0

Questo non ha funzionato fino a quando non ho cambiato 'c.Path = Request.ApplicationPath +"/Pages ";' a 'c.Path = Request.Cookies [i] .Path;' – masty

+0

@masty: Divertente , Request.Cookies [i] .Path non funziona per me. Né c.Path = Request.Cookies [i] .Path + "/ Pages"; Hai installato ServicePack 1 + gli ultimi aggiornamenti cumulativi? –

6
+0

Bella scoperta. Ci proverò. –

+0

FYI, se si utilizza il ReportViewer "standard", questa impostazione può essere modificata in Reporting Services \ ReportServer \ Pages \ ReportViewer.aspx aggiungendo 'KeepSessionAlive =" false "' al tag RS: ReportViewerHost. –

+0

@graham mendick: D'altra parte, se lo fai, visualizzerai un messaggio di errore scaduto sessione se fai clic su Esporta dopo 5-10 minuti di inattività. –

3

Stavo facendo un sacco di difficoltà ad attuare diverse soluzioni a questo problema a causa dell'architettura del nostro sito - per qualsiasi motivo, i miei colleghi hanno avuto origine Ho deciso di utilizzare iframe con collegamenti ai report invece di un controllo di ReportViewer, e non avevo il coraggio di provare a modificare questo così tardi nel processo di sviluppo a causa di un semplice problema relativo ai cookie.

Solutions ho provato che invece no lavoro:

  1. Implementazione Stefan s' code-behind fix - Il codice del server sulla mia pagina non poteva accedere ai cookie di essere impostato nel documento iframe incorporato
  2. Modifica dei cookie dal documento principale in javascript - Per motivi di sicurezza comprensibili, non è stato possibile accedere ai cookie nell'iframe dal codice lato client o
  3. provato il passaggio di parametri nella URL del report di dire che non tenere la seduta viva - Provato aggiungendo "& rs: KeepSessionAlive = False", che non ha causato un errore, ma non ha funzionato
  4. * accarezzato * con l'idea di iniettare javascript into the reports themselves - Considerando questo comporterebbe la modifica di alcuni report 50-dispari e strizzando gli esportati/rapporti salvati sono dotate, questo non era un'opzione

Infine, dopo rovistando il server, mi sono reso conto che il Cartella "Pagine" del server di report (C: \ Programmi \ Microsoft SQL Server \ MSRS1 1.SQLEXPRESS \ Reporting Services \ ReportServer \ Pages) conteneva un documento "ReportViewer.aspx".

E che ne sai? È solo una semplice pagina ASP.NET con un'intestazione dove puoi aggiungere il tuo javascript !?

Quindi, ecco cosa ha funzionato per me:

Ho appena aggiunto il client-side cookie-setting code I had found elsewhere seguente per eliminare tutti i cookie nella pagina ReportViewer, e tutto ad un tratto ha funzionato! Solo un cookie keep-alive alla volta!

<%@ Register TagPrefix="RS" Namespace="Microsoft.ReportingServices.WebServer" Assembly="ReportingServicesWebServer" %> 
 
<%@ Page Language="C#" AutoEventWireup="true" Inherits="Microsoft.ReportingServices.WebServer.ReportViewerPage" %> 
 
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 
 
<html> 
 
<head id="headID" runat="server"> 
 
    <title><%= GetPageTitle() %></title> 
 
</head> 
 
<body style="margin: 0px; overflow: auto"> 
 
    <form style="width:100%;height:100%" runat="server" ID="ReportViewerForm"> 
 
    <asp:ScriptManager ID="AjaxScriptManager" AsyncPostBackTimeout="0" runat="server" /> 
 
    <RS:ReportViewerHost ID="ReportViewerControl" runat="server" /> 
 
    </form> 
 
    <script language="javascript" type="text/javascript"> 
 
     // Beginning of inserted cookies management code 
 
function createCookie(name, value, days) { 
 
    if (days) { 
 
     var date = new Date(); 
 
     date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); 
 
\t var expires = "; expires=" + date.toUTCString(); 
 
    } 
 
    else var expires = ""; 
 

 
    document.cookie = name + "=" + value + expires; 
 
} 
 

 
function readCookie(name) { 
 
    var nameEQ = name + "="; 
 
    var ca = document.cookie.split(';'); 
 
    for (var i = 0; i < ca.length; i++) { 
 
     var c = ca[i]; 
 
     while (c.charAt(0) == ' ') c = c.substring(1, c.length); 
 
     if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length); 
 
    } 
 
    return null; 
 
} 
 

 
function eraseCookie(name) { 
 
    createCookie(name, "", -1); 
 
} 
 

 
var getCookies = function() { 
 
    var pairs = document.cookie.split(";"); 
 
    var cookies = {}; 
 
    for (var i = 0; i < pairs.length; i++) { 
 
     var pair = pairs[i].split("="); 
 
     cookies[pair[0]] = unescape(pair[1]); 
 
    } 
 
    return cookies; 
 
} 
 

 
var pairs = document.cookie.split(";"); 
 
var cookies = {}; 
 
for (var i = 0; i < pairs.length; i++) { 
 
    var pair = pairs[i].split("="); 
 
    cookies[pair[0]] = unescape(pair[1]); 
 
} 
 
var keys = []; 
 
for (var key in cookies) { 
 
    if (cookies.hasOwnProperty(key)) { 
 
     keys.push(key); 
 
    } 
 
} 
 
for (index = 0; index < keys.length; ++index) { 
 
    eraseCookie(keys[index]); 
 
} 
 

 
     // End of inserted cookies management logic 
 

 
     //Beginning of pre-existing code 
 
Sys.WebForms.PageRequestManager.prototype._destroyTree = function(element) { 
 
    var allnodes = element.getElementsByTagName('*'), 
 
     length = allnodes.length; 
 
    var nodes = new Array(length); 
 
    for (var k = 0; k < length; k++) { 
 
     nodes[k] = allnodes[k]; 
 
    } 
 
    for (var j = 0, l = nodes.length; j < l; j++) { 
 
     var node = nodes[j]; 
 
     if (node.nodeType === 1) { 
 
      if (node.dispose && typeof (node.dispose) === "function") { 
 
       node.dispose(); 
 
      } 
 
      else if (node.control && typeof (node.control.dispose) === "function") { 
 
       node.control.dispose(); 
 
      } 
 
      var behaviors = node._behaviors; 
 
      if (behaviors) { 
 
       behaviors = Array.apply(null, behaviors); 
 
       for (var k = behaviors.length - 1; k >= 0; k--) { 
 
        behaviors[k].dispose(); 
 
       } 
 
      } 
 
     } 
 
    } 
 
} 
 
    </script> 
 
</body> 
 
</html>

prega di notare che ci fosse qualche preesistente codice nella pagina che non ho sostituire.

Spero che questo aiuti qualcun altro, dato che ho faticato con questo per un po '!

NOTA: prega di notare che, nel mio caso, la sessione Keep Alive (SKA) biscotti erano non solo HTTP, quindi ero in grado di accedervi dal lato client, anche se solo il lato client all'interno del server di report stesso. enter image description here

+1

È possibile utilizzare una versione più recente di SQL Server. Ho dovuto utilizzare i cookie solo HTTP, una marca di cookie che non è possibile impostare con JavaScript. In realtà ho provato prima questo, e non è riuscito. Potrebbero aver cambiato la loro implementazione.Il mio codice si applica a SQL-Server 2012 ReportingServices, Versione 11.0.5343.0. –

+0

Sì, ho fatto ricorso a questa soluzione solo perché i cookie SKA non sembravano essere solo HTTP. Ho un cookie di autenticazione personalizzato che sto passando dal sito di hosting a SSRS, che è solo HTTP, quindi sono stato sorpreso di vedere che i keep-alive erano diversi. Sto anche usando SSRS 2012, versione 11.0.2100.60. Non sono sicuro se la differenza è dovuta alla versione o ad una configurazione diversa. – DicreetAndDiscrete

+0

In quale pagina apporti queste modifiche? ReportViewer.aspx che vive in C: \ Programmi \ Microsoft SQL Server \ MSRS13.MSSQLSERVER \ Reporting Services \ ReportServer \ Pages per esempio? –