11

Tôi đã chuyển dịch vụ báo cáo SQL Server 2012 (SSRS 2012) thành các hình thức xác thực để chúng tôi có thể sử dụng nó qua internet.SSRS: Tại sao SKA-cookie tích hợp cho đến khi "Yêu cầu HTTP 400 - Yêu cầu quá dài" xảy ra?

Tôi không thể tìm thấy mẫu xác thực biểu mẫu cho SSRS 2012 ở bất kỳ đâu, vì vậy tôi phải lấy SSRS 2008R2 và chỉnh sửa nó cho năm 2012, cho Single-Sign-On (SSO).

Tại thời điểm đó mọi thứ dường như hoạt động như mong đợi; Tôi thậm chí còn quản lý để có được SSO làm việc trên các lĩnh vực.

Nhưng bây giờ tôi có một vấn đề:

Tôi đã kiểm tra tất cả các báo cáo (hơn 200) với Google Chrome, bởi vì tôi đã phải chèn một JavaScript nhỏ mà làm thay đổi td cửa kích thước cho rằng màn HTML ngay không phải IE5-QuirksMode. Sau khi về báo cáo lần thứ 50, tôi đột nhiên nhận được:

"HTTP 400 Bad Request - Yêu Cầu Too Long"

Sau đó, tôi không thể xem bất kỳ báo cáo khác, không phải ngay cả những người đã làm việc trước đó.

Sự cố có vẻ là do quá nhiều cookie và thực sự, khi tôi xóa một vài cookie "* _SKA" (Session Keep Alive?), Nó bắt đầu hoạt động trở lại.

SSRS Sucks

Vấn đề của tôi bây giờ là tôi không biết những gì gây ra này "cookie tràn". Tôi cũng không biết, nếu đây là lỗi trong Chrome, lỗi trong vani SSRS hoặc lỗi do xác thực biểu mẫu mới.

Tất cả tôi làm trong các hình thức mới-xác thực rằng có một cái gì đó để làm với cookie là thế này:

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


    } 


} 

Và như mã này tạo ra "sqlAuthCookie" mà ta thấy ở phía dưới. Chỉ có một "sqlAuthCookie" vì vậy tôi không nghĩ rằng đây có thể là lỗi xác thực biểu mẫu.

Sự cố dường như là các cookie SKA, rằng AFAIK không liên quan gì đến việc xác thực biểu mẫu và mọi thứ liên quan đến Vanilla SSRS.

Điều duy nhất mà tôi có thể xem là lý do cho việc này là thay đổi thời gian chờ của biểu mẫu-xác thực-cookie thành 720 phút mà tôi đã nhập trong phần xác thực biểu mẫu trong tệp web.config.

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

Có ai biết tôi có thể làm gì để tránh bị tràn cookie theo cookie theo cách thủ công không?

Đó là không có vấn đề đối với tôi mỗi gia nhập, ngoài việc nó là rất khó chịu, nhưng nó sẽ là một vấn đề bởi vì người sử dụng có thể sẽ không thể rất hiểu biết về điều đó ...

Trả lời

8

Issue liệt kê như là cố định trong SQL Server 2012 SP1 CU7. (xem nhận xét từ Microsoft trong connect issue)
Nhưng vẫn có trong SQL-Server 2014.


Phần sau được áp dụng, nếu bạn không thể cài đặt SQL Server 2012 SP1 CU7:

OK, có câu trả lời bản thân mình.

Cookie tiếp tục được phát hành mỗi khi một người mở một báo cáo.
Bây giờ, điều đó trở thành vấn đề khi một người mở (hoặc làm mới hoặc thay đổi trang khác), nói rằng, hơn 110 - 120 báo cáo, mà không đóng trình duyệt.

Vì vậy, chúng tôi bảo vệ bằng cách xóa các cookie dư thừa và đặt ranh giới an toàn tại appx. 1/2 trong số tối đa giả định là 120 cookie.

Cookie là HttpOnly và hết hạn khi một cookie đóng trình duyệt (cookie phiên).
Chúng là cookie HttpOnly không an toàn, đó là lý do tôi thất bại trong nỗ lực xóa chúng qua JavaScript.
Vì vậy, cần xóa chúng ở phía máy chủ. Vì chúng ta không thể sửa đổi ReportServer, chúng ta phải sử dụng inline-scripting.

<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

Đóng trình duyệt không hoạt động với Chrome. Tôi phải xóa cookie theo cách thủ công. Tôi sẽ sớm thử giải pháp phía máy chủ của bạn. Cảm ơn! – kravits88

+0

Điều này không hiệu quả đối với tôi cho đến khi tôi thay đổi 'c.Path = Request.ApplicationPath +"/Pages ";' đến 'c.Path = Request.Cookies [i] .Path;' – masty

+0

@masty: Funny , Request.Cookies [i] .Path không hoạt động cho tôi. Không phải c.Path = Request.Cookies [i] .Path + "/ Pages"; Bạn đã cài đặt ServicePack 1 + bản cập nhật tích luỹ mới nhất chưa? –

6

Bạn có thể đặt KeepSessionAlive false trên ReportViewer kiểm soát http://msdn.microsoft.com/en-us/library/microsoft.reporting.webforms.reportviewer.keepsessionalive(v=vs.100).aspx

+0

Rất đẹp. Tôi sẽ thử xem. –

+0

FYI, nếu bạn đang sử dụng ReportViewer "chuẩn", cài đặt này có thể được thay đổi trong Reporting Services \ ReportServer \ Pages \ ReportViewer.aspx bằng cách thêm 'KeepSessionAlive =" false "' vào thẻ RS: ReportViewerHost. –

+0

@graham mendick: Mặt khác, nếu bạn làm điều đó, bạn sẽ nhận được thông báo lỗi hết hạn phiên nếu bạn nhấp vào xuất sau 5 đến 10 phút không hoạt động. –

3

Tôi đã gặp rất nhiều khó khăn trong việc thực hiện các giải pháp khác nhau cho vấn đề này vì kiến ​​trúc trang web của chúng tôi - vì lý do gì, đồng nghiệp của tôi đã ban quyết định sử dụng iframes với các liên kết đến các báo cáo thay vì một điều khiển ReportViewer, và tôi đã không muốn thử và thay đổi điều này quá muộn trong quá trình phát triển do một vấn đề cookie đơn giản.

Solutions tôi đã cố gắng mà không công việc:

  1. Thực hiện Stefan 's code-behind sửa chữa - Mã máy chủ trên trang của tôi không thể truy cập các tập tin cookie được thiết lập trong tài liệu iframe nhúng
  2. Thay đổi cookie từ tài liệu gốc trong javascript - Vì lý do bảo mật dễ hiểu, tôi không thể truy cập cookie trong khung nội tuyến từ mã phía máy khách hoặc
  3. Cố gắng truyền tham số vào URL của báo cáo nói nó không phải để giữ phiên sống - Cố gắng thêm "& rs: KeepSessionAlive = False", mà không gây ra một lỗi, nhưng đã không làm việc
  4. * đùa giỡn * với ý tưởng về tiêm javascript into the reports themselves - Xem xét điều này sẽ liên quan đến việc thay đổi một số báo cáo 50-lẻ và screwing lên xuất khẩu/báo cáo đã lưu đặc trưng, ​​đây không phải là một lựa chọn

Cuối cùng, sau khi chọc xung quanh máy chủ, tôi nhận ra rằng Báo cáo Máy chủ "Trang" thư mục (C: \ Program Files \ Microsoft SQL Server \ MSRS1 1.SQLEXPRESS \ Reporting Services \ ReportServer \ Pages) chứa một tài liệu "ReportViewer.aspx".

Và bạn biết điều gì? Nó chỉ là một trang ASP.NET đơn giản với một tiêu đề, nơi bạn có thể thêm javascript của riêng bạn !?

Vì vậy, đây là những gì DID làm việc cho tôi:

Tôi chỉ cần thêm các client-side cookie-setting code I had found elsewhere dưới đây để xóa tất cả các tập tin cookie trên trang ReportViewer, và tất cả mọi thứ đột nhiên làm việc! Chỉ có một cookie duy trì tại một thời điểm!

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

Xin lưu ý rằng có một số tồn tại trước đó mã trong trang mà tôi không thể thay thế.

Hy vọng điều này sẽ giúp người khác, vì tôi đã vật lộn với điều này một thời gian!

LƯU Ý: Xin lưu ý rằng, trong trường hợp của tôi, Session Keep Alive (SKA) cookie không HTTP-chỉ, vì vậy tôi đã có thể truy cập chúng từ phía khách hàng, mặc dù chỉ là client-side trong chính Máy chủ báo cáo. enter image description here

+1

Bạn có thể sử dụng phiên bản máy chủ SQL mới hơn. Tôi đã phải sử dụng cookie chỉ HTTP, một thương hiệu cookie mà bạn không thể đặt bằng JavaScript. Tôi thực sự đã thử điều này đầu tiên, và nó đã thất bại. Họ có thể đã thay đổi thực hiện của họ.Mã của tôi áp dụng cho SQL-Server 2012 ReportingServices, Phiên bản 11.0.5343.0. –

+0

Có, tôi chỉ sử dụng giải pháp này vì các cookie SKA dường như không phải là chỉ HTTP. Tôi có một cookie xác thực tùy chỉnh Tôi đang đi từ trang web lưu trữ để SSRS, đó là chỉ HTTP, vì vậy tôi đã ngạc nhiên khi thấy rằng các tổ chức khác nhau. Tôi cũng đang sử dụng SSRS 2012, phiên bản 11.0.2100.60. Không chắc chắn nếu sự khác biệt là do phiên bản hoặc cấu hình khác. – DicreetAndDiscrete

+0

Trang nào bạn thực hiện những thay đổi này? ReportViewer.aspx sống trong C: \ Program Files \ Microsoft SQL Server \ MSRS13.MSSQLSERVER \ Reporting Services \ ReportServer \ Pages chẳng hạn? –