【问题标题】:Actions on Google account linking对 Google 帐户关联的操作
【发布时间】:2017-06-01 15:28:39
【问题描述】:

根据here 描述的文档,我设置了隐式授权的帐户链接,并发现它在使用浏览器/操作控制台以及适用于 Android 的 Google Home 应用程序进行测试时效果很好。不幸的是,在应用程序的 iphone 版本上,用户身份验证大部分时间都挂起。来自谷歌支持行动的反馈是,问题在于谷歌登录流程是在单独的浏览器选项卡(窗口)中实现的。在 iphone 上,您无法在 SfariViewController 中打开 2 个窗口,因此它们正在重写第一页的地址,无法完成登录流程。这是已知问题,他们不打算改变这一点。解决方案是在一个浏览器窗口中实现所有登录流程。我不清楚如何执行此操作,并且正在寻找某人在您设置的授权 URL 后面共享代码,该 URL 始终在 iphone 上运行。以下是我正在使用的核心:

.html sn-p:

<!DOCTYPE html>
<html>
<head>
  <title>Authorization Page</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="google-signin-client_id" content="948762963734-2kbegoe3i9ieqc6vjmabh0rqqkmxxxxx.apps.googleusercontent.com">
  <!-- <meta name="google-signin-ux_mode" content="redirect"> INCLUDING THIS META TAG BREAKS THE AUTH FLOW -->
  <script src="js/googleAuth.js"></script>
  <script src="https://apis.google.com/js/platform.js" async defer></script>
  <link rel="stylesheet" href="css/googleAuth.css">   
  <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Raleway">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">  
</head>
<body>
<header class="bgimg-1 w3-display-container w3-grayscale-min" id="loginScreen">
  <div class="w3-display-topleft w3-padding-xxlarge w3-text-yellow" style="top:5px"> 
    <span class="w3-text-white">Google Sign In</span><br>
    <span class="w3-large">Sign in with your Google account</span><br><br>
    <div class="g-signin2" data-onsuccess="onSignIn"></div><br><br>        
  </div>   
</header>
</body>
</html>

.js代码sn-p:

function onSignIn(googleUser) {
  var profile = googleUser.getBasicProfile();
  var id = profile.getId()
  var name = profile.getName()
  var email = profile.getEmail()
  var token = googleUser.getAuthResponse().id_token;
  var client_id = getQueryVariable('client_id')
  // vital-code-16xxx1 is the project ID of the google app
  var redirect_uri = 'https://oauth-redirect.googleusercontent.com/r/vital-code-16xxx1'
  var state = getQueryVariable('state')
  var response_type = getQueryVariable('response_type')

  // store the user's name, ID and access token and then sign out
  storeOwnerID (email, name, id, token, function() {
    // sign out
    var auth2 = gapi.auth2.getAuthInstance();
    auth2.signOut().then(function () {
      console.log('signed out')
    });
    // if this page was loaded by Actions On Google, redirect to complete authorization flow
    typeof redirect_uri != 'undefined' ? window.location = redirectURL : void 0    
  }) 
}

function getQueryVariable(variable) {
  var query = window.location.search.substring(1);
  var vars = query.split('&');
  for (var i = 0; i < vars.length; i++) {
    var pair = vars[i].split('=');
    if (decodeURIComponent(pair[0]) == variable) {
      return decodeURIComponent(pair[1]);
    }
  }
  console.log('Query variable %s not found', variable);
}

【问题讨论】:

  • 您介意发布代码的 sn-p 以重现您的问题中的问题吗?否则很难理解这个问题。
  • @TMSCH 我已经包含了代码 sn-ps。 TIA
  • 当您说它破坏了身份验证流程时,您是指帐户链接流程吗?我认为问题在于,在 Google 登录重定向之后,URL 中不再存在“state”、“response_type”和“client_id”查询参数。在重定向到 Google 登录之前,您必须将它们存储在持久存储(localStorage 或 indexedDb)中,并在重定向后从那里读取它们。这有意义吗?
  • 这确实是问题的一部分。我将在下面记录完整的解决方案。
  • 如何在移动应用程序中添加帐户链接,我正在开发 iOS 移动应用程序以使用 Dialogflow 技能。我需要坚持用户对 userID 的请求,我该如何实现我的要求?

标签: ios iphone google-oauth actions-on-google


【解决方案1】:

@dana 你试过添加元标记吗?

<meta name="google-signin-ux_mode" content="redirect">

【讨论】:

  • 包括 会中断设置为使用来自帐户链接流程的 URL 进行的自动重定向(例如: assistant.google.com/services/auth/handoffs/auth/…) 。我收到错误“错误:redirect_uri_mismatch”。我花时间确保在 API Access 下的云控制台项目下正确设置了重定向 URI,并且确实如此。真正的问题是无法识别该元标记 googleUser.getBasicProfile。
  • 感谢您的帮助,这是解决方案的重要组成部分。
【解决方案2】:

在 Google 支持和工程部门的帮助下,该问题现已得到解决:

  1. 如上所述,我必须包含这个元标记:&lt;meta name="google-signin-ux_mode" content="redirect"&gt;
  2. 我需要在我的项目的授权重定向 URI 中包含 https://my-auth-endpoint.com/。仅在授权的 javascript 来源中拥有它是不够的。另一个关键是包含斜杠,我最初没有,如果没有它,它将无法工作。

下面是简单的代码基础,您可以使用它来获取授权端点的工作版本,以便对 google 帐户链接进行操作:

.html:

<!DOCTYPE html>
<html>
<head>
  <title>Authorization Page</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="google-signin-client_id" content="948762963734-2kbegoe3i9ieqc6vjmabh0rqqkmxxxxx.apps.googleusercontent.com">
  <meta name="google-signin-ux_mode" content="redirect">
  <script src="js/googleAuth.js"></script>
  <script src="https://apis.google.com/js/platform.js" async defer></script>
  <link rel="stylesheet" href="css/googleAuth.css">   
  <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Raleway">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">  
  <script>
    sessionStorage['jsonData'] == null ? storeQueryVariables() : void 0
  </script>
</head>
<body>
<header class="bgimg-1 w3-display-container w3-grayscale-min" id="loginScreen">
  <div class="w3-display-topleft w3-padding-xxlarge w3-text-yellow" style="top:5px"> 
    <span class="w3-text-white">Google Sign In</span><br>
    <span class="w3-large">Sign in with your Google account</span><br><br>
    <div class="g-signin2" data-onsuccess="onSignIn"></div><br><br>        
  </div>   
</header>
</body>
</html>

.js:

// Retrieve user data, store to DynamoDB and complete the redirect process to finish account linking
function onSignIn(googleUser) {
  let profile = googleUser.getBasicProfile(),
      id = profile.getId(),
      name = profile.getName(),
      email = profile.getEmail(),
      token = googleUser.getAuthResponse().id_token,
      redirect_uri = 'https://oauth-redirect.googleusercontent.com/r/vital-code-16xxxx',
      jsonData = JSON.parse(sessionStorage['jsonData']),
      redirectURL = redirect_uri + '#access_token=' + token + '&token_type=bearer&state=' + jsonData.state

  // store the user's name, ID and access token
  storeUserData(email, name, id, token, function() {
    // sign out of google for this app
    let auth2 = gapi.auth2.getAuthInstance();
    auth2.signOut()
    // if this page was loaded by Actions On Google, redirect to complete authorization flow
    typeof redirect_uri != 'undefined' ? window.location = redirectURL : void 0    
  })   
}

// Store the user data to db
function storeUserData (email, name, id, token, callback) {
  // removed for simplicity
}

// Store URI query variable 'state' to browser cache
function storeQueryVariables() {
  let qvar = {
    'state': getQueryVariable('state')
  }
  storeLocally(qvar)
}

// Get any variable from incoming URI
function getQueryVariable(variable) {
  var query = window.location.search.substring(1);
  var vars = query.split('&');
  for (var i = 0; i < vars.length; i++) {
      var pair = vars[i].split('=');
      if (decodeURIComponent(pair[0]) == variable) {
          return decodeURIComponent(pair[1]);
      }
  }
  console.log('Query variable %s not found', variable);
}

// Store JSON object input to local browser cache 
function storeLocally (jsonData) {
  if (typeof(Storage) !== 'undefined') {
    sessionStorage['jsonData'] = JSON.stringify(jsonData)
  } else {
    console.log('Problem: local web storage not available')
  }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多