【问题标题】:How to implement Tableau Trusted Authentication?如何实现 Tableau 可信身份验证?
【发布时间】:2019-04-11 01:47:50
【问题描述】:

1) 在 Web 应用程序中查看嵌入式仪表板时,系统会提示用户登录 Tableau。

2) 如果他们关闭浏览器、启动不同的浏览器会话或让 Tableau cookie 过期,系统将提示他们再次登录。

3) 在一天中,您可能会在尝试查看仪表板时被提示多次登录。这很快就会变得烦人和厌烦。

Tableau 提供了一种称为“可信身份验证”的解决方案,它绕过了手动登录过程。经过一周的调试和故障排除,我能够做到这一点。我在 Stackoverflow 上找不到任何解决方案,所以我想分享一下我是如何做到这一点的,希望能帮助到其他人。

【问题讨论】:

    标签: javascript c# asp.net embed tableau-api


    【解决方案1】:

    我就是这样做的

        [NonAction]
        private static async Task<String> GetTableauStringAsync(string userForTableau)
        {
    
            string postData = "username="+ userForTableau;
            byte[] data = System.Text.Encoding.ASCII.GetBytes(postData);
            var myTicket = "";
    
            try
            {
    
                HttpWebRequest req = (HttpWebRequest)WebRequest.Create("https://myTableauServer.com/trusted");
    
                req.Method = "POST";
                req.ContentType = "application/x-www-form-urlencoded";
                req.ContentLength = postData.Length;
    
                Stream outStream = req.GetRequestStream();
                outStream.Write(data, 0, data.Length);
                outStream.Close();
    
                HttpWebResponse res = (HttpWebResponse)req.GetResponse();
                StreamReader inStream = new StreamReader(res.GetResponseStream());
                string resString = inStream.ReadToEnd();
                inStream.Close();
    
                myTicket = resString;
            }
            catch (Exception ex)
            {
                string exceptionMessage = ex.Message;
                string innerException = ex.InnerException.Message;
    
                myTicket = "ERROR";
            }
    
            return myTicket;
        }
    

    控制器

        [HttpGet]
        public async Task<ActionResult> Index()
        {        
            string resultText = String.Empty;
    
            var task = GetTableauStringAsync(subjectName);
            var result = await task;
            resultText = result;
    
            ViewBag.TableauTicket = resultText ?? " _";
            return View();
        }
    

    Java 脚本

    @section Scripts {
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
    <script type="text/javascript">
    
        $(document).ready(function () {
                var myTicket = $("#lblTableauTicket").text();
                var patientBKVal = $("#lblPatient_BK").text();
                var destination = "https://myTableauServer.com/trusted/" + myTicket + "/views/MyScorecard_15804618842350/MyScorecard?Patient_BK=" + patientBKVal + "&iframeSizedToWindow=true&:embed=y&:showAppBanner=false&:display_count=no&:showVizHome=no&:origin=viz_share_link";
                window.location.href = destination;
        });
    
    </script>
    
    }
    

    【讨论】:

      【解决方案2】:

      链接到 Tableau 的How Trusted Authentication Works

      关于我如何实施可信身份验证的高级视图

      1) Tableau Server 必须有一个 wgserver.trusted_hosts 文件的条目,其中包含您的 Web 应用程序的主机名,才能使上述任何一项工作。

      2) 传递三个重要参数:

      username          212456449
      server            http://[server]
      target_site       YourTargetSiteName
      

      3) 如果 HTTP POST 请求有效且用户拥有正确的 Tableau 许可证,Tableau 会创建一个 48 个唯一字符的票证,该票证仅在 3 分钟内有效。

      4) 在 Tableau 兑换之前,我以编程方式将 48 个唯一字符票证添加到嵌入式 JavaScript 中。

      代码在我的网络应用程序中的工作原理

      我创建了一个包含两个方法的 TrustedAuth 类:requestTicket()addTicket()requestTicket() 是一种异步方法,它采用三个必需参数(sso、服务器、站点)。 HTTP POST 被触发并等待响应。如果 Tableau 响应为 -1 ,则 HTTP 握手失败或用户无效。如果有效,响应将是一个 48 个字符的加密字符串。

      addTicket() 是一种同步方法,它采用两个参数(ticket、reportLink)。此方法采用 48 个字符的加密票据并将其附加到嵌入式 JavaScript (reportLink)。

      Web 应用程序向 Tableau 发送一个 HTTP GET 请求,其中包括带有加密票证的嵌入式 JavaScript (reportLink)。 Tableau Server 兑换票证,创建会话,将用户登录,未显示登录提示

      TrustedAuth 类

      public class TrustedAuth
      {
          public async Task<string> requestTicket(int sso, string server, string site)
          {
              try
              {
                  //Assign parameters and values
                  var values = new List<KeyValuePair<string, string>>();
                  values.Add(new KeyValuePair<string, string>("username", sso.ToString()));
                  values.Add(new KeyValuePair<string, string>("target_site", site));
      
                  //Web Application is HTTP and Tableau is HTTPS, there are certification issues. I need to fake the certs out and return them as true.
                  System.Net.ServicePointManager.ServerCertificateValidationCallback = (senderX, certificate, chain, sslPolicyErrors) => { return true; };
      
                  //Instantiate HttpClient class
                  var client = new HttpClient();
      
                  //Encode Content
                  var req = new HttpRequestMessage(HttpMethod.Post, server) { Content = new FormUrlEncodedContent(values) };
      
                  //POST request
                  var res = await client.SendAsync(req);
      
                  //Get response value
                  var responseString = await res.Content.ReadAsStringAsync();
      
                  return responseString;
      
              }
              catch (Exception e)
              {
                  System.IO.File.AppendAllText(@"c:\inetpub\wwwroot\WebApplication\TrustedAuthError.txt", ":::ERROR::: " + System.DateTime.Today.ToString() + ":::" + e.ToString() + Environment.NewLine);
                  //Add Log4Net logging
              }
      
              return "-1";
      
          }
      
          public string addTicket(string ticket, string reportLink)
          {
              //Add ticket parameter with ticket value. I'm using </object> as my keyword to find and replace
              string addedTicket = reportLink.Replace("</object>", "<param name='ticket' value='" + ticket + "' /></object>");
      
              return addedTicket;
          }
      }
      

      仪表板控制器

      public async Task<ActionResult> Dashboard(int Report_Num)
          {
           //db will be your database model where your Report_Link is stored
           Report_Completion_Status_NEW report_Completion_Status = db.Report_Completion_Status_NEW.Find(Report_Num);
      
           if (report_Completion_Status == null)
              {
                  return HttpNotFound();
              }
      
              var ticket = "";
              //Get Trusted Tableau Authentication Ticket
              try
              {
                  //For example purposes, I'm hard-coding the Tableau Server Name and Site Name for the example _trustedAuth.requestTicket method. In my actual code, I'm storing these in my web.config. 
                  ticket = await _trustedAuth.requestTicket(b.getSSO(User.Identity.Name), "https://ProdTableauUrlGoesHere.com/trusted", "YourTargetSiteNameHere");
              }
              catch
              {
                  ticket = "-1";
              }
      
              //Only add trusted Tableau Authentication ticket if it's valid, else kick user to default Report_Link which will make them login manually. 
              //You get a nasty error message if you pass in a '-1'
              if (!ticket.Equals("-1"))
              {
                  ViewBag.Link = _trustedAuth.addTicket(ticket.ToString(), report_Completion_Status.Report_Link);
              }
              else
              {
                  ViewBag.Link = report_Completion_Status.Report_Link;
              }
      
              var model = await this.GetFullAndPartialViewModel(Report_Num);
      
              return this.View(model);
          }
      

      插入了工单参数的新嵌入式 JavaScript (reportLink)

      仪表板视图

      @model WebReportingToolDAL.Models.ViewModels.ReportCategoryListModel
      @{
          ViewBag.Title = "Dashboard";
          Layout = "~/Views/Shared/_Layout.cshtml";
      }
      
       <body>
          @Html.Raw(ViewBag.Link)
      </body>
      

      如果一切正常,您应该不会再看到 Tableau 登录页面。

      【讨论】:

      • 能否为“report_Completion_Status”添加代码?现在出现编译错误
      • 是的,我更新了原始答案。您应该看到 report_Completion_Status 是如何填充的。我从 report_Completion_Status 中提取的唯一值是 Report_Link,它是一个数据类型字符串。
      • 我添加了更多的 cmets 并更新了答案中的代码。希望这会有所帮助。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多