如何为网站上部署的chatbot配置SSO [英] How to configure SSO for chatbot deployed on website

查看:51
本文介绍了如何为网站上部署的chatbot配置SSO的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用以下代码配置SSO.

I am trying to configure SSO using the below code.

  <!DOCTYPE html>
<html>
<head>
<title>Contoso Sample Web Chat</title>
<script src="https://cdn.botframework.com/botframework-webchat/latest/webchat.js"></script>
<script type="text/javascript" src="https://alcdn.msauth.net/lib/1.2.0/js/msal.js"></script>
<script src="https://unpkg.com/@azure/storage-blob@10.3.0/browser/azure-storage.blob.min.js"
  integrity="sha384-fsfhtLyVQo3L3Bh73qgQoRR328xEeXnRGdoi53kjo1uectCfAHFfavrBBN2Nkbdf"
  crossorigin="anonymous">
</script>
<script type="text/javascript">
  if (typeof Msal === 'undefined') document.write(unescape("%3Cscript src='https://alcdn.msauth.net/lib/1.2.0/js/msal.js' type='text/javascript' %3E%3C/script%3E"));
</script>

  <style>
  html,
  body {
    height: 100%;
  }

  body {
    margin: 0;
  }

  .modal {
    display: none; /* Hidden by default */
    position: fixed; /* Stay in place */
    z-index: 1; /* Sit on top */
    padding-top: 100px; /* Location of the box */
    left: 0;
    top: 0;
    width: 100%; /* Full width */
    height: 100%; /* Full height */
    overflow: auto; /* Enable scroll if needed */
    background-color: rgb(0, 0, 0); /* Fallback color */
    background-color: rgba(0, 0, 0, 0.4); /* Black w/ opacity */
  }

  .modal-content {
    background-color: #fefefe;
    margin: auto;
    padding: 10px;
    border: 1px solid #888;
    width: 500px;
    height: 575px;
  }
  .close {
    color: black;
    float: right;
    font-size: 28px;
    font-weight: bold;
  }

  .close:hover,
  .close:focus {
    color: #000;
    text-decoration: none;
    cursor: pointer;
  }

  .main {
    margin: 18px;
    border-radius: 4px;
  }

  div[role="form"] {
    background-color: #3392ff;
  }

  #webchat {
    position: center;
    height: 530px;
    width: 100%;
    top: 60px;
    overflow: hidden;
  }
  #heading {
    padding-bottom: 5px;
  }

  h1 {
    font-size: 14px;
    font-family: Segoe UI;
    font-style: normal;
    font-weight: 600;
    font-size: 14px;
    line-height: 20px;
    color: #f3f2f1;
    letter-spacing: 0.005em;
    display: table-cell;
    vertical-align: middle;
    padding: 13px 0px 0px 20px;
  }

  /*#chatwindow
{
  height: 530px;
  width: 100%;
  overflow: hidden;
top: 60px;
 position: center;
}*/

  #login {
    position: fixed;
    margin-left: 150px;
  }

  .span {
    font-weight: bold;
  }
  #myBtn {
    position: fixed;
    float: right;
    outline: none;
    width: 60px;
    height: 80px;
    margin: auto auto auto 10px;
  }
  button:hover {
    background-color: transparent;
  }
  </style>

</head>

<body>
  <button id="myBtn" type="button">Power Virtual Agent</button>
  <div id="myModal" class="modal">
  <div class="modal-content" style="background-color: #ffd933">
     <span class="close">&times;</span>
<div id="chatwindow">
  <div id="heading">
    <div><span>SSO Test Bot</span></div>
  </div>
  <!-- <div style="z-index: 100;position: absolute;margin-top: 50px;width: 100%;">
     <div>
      <label id="userName" name="userName" style="width:75%;height:15px;border-color: Transparent;">Not logged in.</label>
      <button id="login" name="login" onclick="onSignInClick()">Log In</button>
    </div>
  </div> -->
  <div id="webchat"></div>
</div>
</div>
</div>



<script>
  //Button code begins here
  // Get the modal
  var modal = document.getElementById("myModal");

  // Get the button that opens the modal
  var btn = document.getElementById("myBtn");

  // Get the <span> element that closes the modal
  var span = document.getElementsByClassName("close")[0];

  // When the user clicks the button, open the modal
  btn.onclick = function () {
    modal.style.display = "block";
  };

  // When the user clicks on <span> (x), close the modal
  span.onclick = function () {
    modal.style.display = "none";
  };

  // When the user clicks anywhere outside of the modal, close it
  window.onclick = function (event) {
    if (event.target == modal) {
      modal.style.display = "none";
    }
  };
  //Button code ends here
</script>



<script>

function onSignin(idToken)
{
  alert("KMT - Inside onSignin: " + idToken);
  let user = clientApplication.getAccount();
  alert("KMT - user.name: " + user.name);
  document.getElementById("userName").innerHTML = "Currently logged in as " + user.name;
  let requestObj1 = {
    scopes: ["user.read", 'openid', 'profile']
  };
}

function onSignInClick()
{
  //console.log("Inside onSignInClick");
  let requestObj = {
    scopes: ["user.read", 'openid', 'profile']
  };

  clientApplication.loginPopup(requestObj).then(onSignin).catch(function (error) {console.log(error) });
}

function getOAuthCardResourceUri(activity) {
  if (activity && activity.attachments && activity.attachments[0] &&
       activity.attachments[0].contentType === 'application/vnd.microsoft.card.oauth' &&
       activity.attachments[0].content.tokenExchangeResource) {
     // asking for token exchange with AAD
         return activity.attachments[0].content.tokenExchangeResource.uri;
   }
}

function exchangeTokenAsync(resourceUri) {
  let user = clientApplication.getAccount();
  if (user) {
     let requestObj = {
       scopes: ["user.read", 'openid', 'profile']
     };
  return clientApplication.acquireTokenSilent(requestObj).then(function (tokenResponse) {
    return tokenResponse.accessToken;
     })
     .catch(function (error) {
       console.log(error);
     });
     }
     else {
     return Promise.resolve(null);
   }
}

async function fetchJSON(url, options = {}) {
    const res = await fetch(url, {
      ...options,
      headers: {
           ...options.headers,
           accept: 'application/json'
      }});

      if (!res.ok)
      {
        throw new Error(`Failed to fetch JSON due to ${res.status}`);
      }

      return await res.json();
  }
</script>

<script>
     var clientApplication;
     (function ()
     {
       var msalConfig = {
         auth:{
               clientId: '7dd5c894-17f5-4fd1-be79-cb4900590418',
               authority: 'https://login.microsoftonline.com/e7ee4711-c0b1-4311-b500-b80d89e5b298'
         },
         cache:{
               cacheLocation: 'localStorage',
               storeAuthStateInCookie: true
         }};
       if (!clientApplication)
       {
            clientApplication = new Msal.UserAgentApplication(msalConfig);
       }
     } ());

(async function main() {

  // Add your BOT ID below

  var BOT_ID = "ec06d968-e213-4d13-90c7-fe78bcadbfa6";
  var theURL = "https://powerva.microsoft.com/api/botmanagement/v1/directline/directlinetoken?botId=" + BOT_ID;

    var userId = clientApplication.account?.accountIdentifier != null ?
                    ("You-customized-prefix" + clientApplication.account.accountIdentifier).substr(0, 64)
                    : (Math.random().toString() + Date.now().toString()).substr(0,64);

  const { token } = await fetchJSON(theURL);
  //console.log("Token inside main: " + JSON.parse(token));

  const directLine = window.WebChat.createDirectLine({ token });
  //console.log("directLine inside main: " + directLine);

  const store = WebChat.createStore({}, ({ dispatch }) => next => action => {const { type } = action;
  //console.log("store inside main: " + JSON.parse(store));

  if (action.type === 'DIRECT_LINE/CONNECT_FULFILLED')
  {
           dispatch({
              type: 'WEB_CHAT/SEND_EVENT',
               payload:
             {
                  name: 'startConversation',
                  type: 'event',
                  value:
                {
                    text: "hello"
                }
               }
              });
               return next(action);
   }
   if (action.type === 'DIRECT_LINE/INCOMING_ACTIVITY')
   {
         const activity = action.payload.activity;
         let resourceUri;
         if (activity.from && activity.from.role === 'bot' && (resourceUri = getOAuthCardResourceUri(activity)))
       {
            exchangeTokenAsync(resourceUri).then(function (token) {
            if (token)
          {
            //console.log("Inside if token: " + token);
                   directLine.postActivity({
                         type: 'invoke',
                         name: 'signin/tokenExchange',
                         value:
                     {
                             id: activity.attachments[0].content.tokenExchangeResource.id,
                             connectionName: activity.attachments[0].content.connectionName,
                             token
                         },
                         "from":
                     {
                             id: userId,
                             name: clientApplication.account.name,
                             role: "user"
                         }
                       }).subscribe(id => {
                            if (id === 'retry')
                        {   // bot was not able to handle the invoke, so display the oauthCard
                                return next(action);
                            }   // else: tokenexchange successful and we do not display the oauthCard
                         },
                         error => {
                                // an error occurred to display the oauthCard
                                return next(action);
                         }
          );
          return;
        }
      else return next(action);
    });
    }
  else return next(action);
  }
  else return next(action);
  });

  const styleOptions = {
     // Add styleOptions to customize Web Chat canvas
     hideUploadButton: true
  };


    window.WebChat.renderWebChat({
            directLine: directLine,
        store,
              userID:userId,
        styleOptions
          },
          document.getElementById('webchat')
    );
})().catch(err => console.error("An error occurred: " + err));
</script>
</body>
</html>

每次我单击Power Virtual Agent按钮时,都会在漫游器中看到登录的OAuth卡.

Every time I click on the Power Virtual Agent button I see the login OAuth card in the bot.

Chatbot OAuth卡图像

我要寻找的是我不希望显示登录OAuth卡.相反,我想直接登录,因为我已经登录到SharePoint网站.

What I am looking for is I do not want the login OAuth card to be displayed. Instead I wanted to be logged in directly as I have already login to my SharePoint website.

我已经在文档

推荐答案

不幸的是,SharePoint Online无法将bot服务与SharePoint SSO集成.无法从SharePoint获取AAD令牌并将其发送给机器人以供使用.

Unfortunately, SharePoint SSO integration with bot service is not possible with SharePoint Online, which is much more restrictive. There is no way to get the AAD token from SharePoint and send to the bot for use.

作为一种解决方法,您只能将已登录用户的UserID传递给bot,以便它可以通过调用图形API/SharePoint API来获取访问令牌以使用资源,再次获取新的访问令牌以进行访问Bot中使用应用"权限的用户/SP详细信息.

As a workaround, you can only pass the UserID of logged in user to the bot, so that it can fetch the access token to use resources by invoking the graph API/SharePoint API, to again fetch the new access token to access user/SP details using App permissions in the Bot.

但是此方法存在安全问题,拥有Bot Directline令牌的任何人都可以传递任何有效的电子邮件ID,并且进一步,它将使用Bot中的AAD应用程序权限来获取该用户(提供的电子邮件ID)详细信息的访问令牌..但是最终,这些用户和电子邮件ID只能来自您组织的租户.我不能说这是安全/防暴的.

But there is security catch with this approach, anyone who has the Bot directline token, can pass any valid email id, and further it will fetch access token for that user’s (supplied email id) details using AAD app permission in the Bot. But ultimately those users and email id can only be from your organization's tenant. I can't say that it's secure/ temper proof.

这只是一个变通办法,因为SharePoint Online无法与机器人服务集成SharePoint SSO.如果您不希望用户使用AAD重新进行身份验证,则此(替代方法)是目前唯一可用的选项.

This is just a workaround as SharePoint SSO integration with bot service is not possible with SharePoint Online. If you don’t want users to re-authenticate with AAD, this (workaround) is the only available option at the moment.

这篇关于如何为网站上部署的chatbot配置SSO的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆