【问题标题】:Unity and Google OAuth2 Authorization Code FlowUnity 和 Google OAuth2 授权代码流
【发布时间】:2025-12-11 15:10:01
【问题描述】:

我正在尝试构建一个使用 WebGL 部署的 Unity 应用程序。我正在尝试将 Google Sign-In 合并到应用程序中,到目前为止,这就是我在 Chrome 中的 Unity WebGL 构建中成功完成的工作:

  1. 用户在 Unity 应用程序的 Tab A 中按下“使用 Google 登录”按钮。
  2. 用户被定向到另一个选项卡 B 上的 Google 登录页面。
  3. 用户使用 Google 帐户登录,并被重定向到我的redirect_uri,即https://localhost,带有auth 代码参数。

我的问题是,我是否可以使用.jslib 文件执行以下操作:

  1. 不要在标签 B 上转到 redirect_uri,而是在不重新加载的情况下返回标签 A,并传递 auth 代码。
  2. 在上面一行的基础上,有 javascript 处理程序,即:
    1. 收到授权码后,按照here的指示,发起id_token交换授权码的请求。
    2. 收到 id_token 后,调用 C# 脚本函数对 id_token 执行进一步操作。

或者,我可以将 redirect_uri 设置为我的后端服务器上的端点,并使用 Google 客户端 SDK 执行身份验证令牌 -> id_token 流程。但是,对于这种方法,我想知道我是否能够

  1. 在后端服务器完成auth token -> id_token流程后,关闭当前窗口Tab B,返回Tab A。
  2. 返回选项卡 A 后,将 Unity 重定向到特定场景(不再是登录场景,而是用户通过身份验证后被定向到的主页)。

非常感谢我能得到的任何帮助:')

编辑:为了更清楚,我想要实现的是 FacebookSDK for Unity 在他们的FB.LogInWithReadPermissions() 中所做的事情。整个身份验证代码 -> access_token 流程是无缝的,我在最后使用 access_token 重定向回 Tab A 中的 Unity 应用程序。

【问题讨论】:

    标签: javascript unity3d oauth-2.0 google-oauth facebook-unity-sdk


    【解决方案1】:

    我设法找到了一个 Javascript 解决方案来实现我的第一个方法。不同之处在于,因为

    1. 我的应用程序永远不会投入生产
    2. 与我的 Facebook OAuth 实施保持一致,

    我使用了隐式流而不是授权码流,尽管出于安全考虑它不是推荐的方式。但是,我认为您可以轻松地使用授权代码流程,检索授权代码并将其传递到您的后端以交换 id 令牌。 (据我所知,您不能使用 Javascript/XHR 请求进行此交换)

    所以,流程是从我的 C# 脚本中,我从 .jslib 文件中调用 Javascript 函数。基本上,该函数检测 OAuth 窗口何时重定向回我的 redirect_uri,然后从重定向的 URI 中获取 access_token 参数,并调用 C# 脚本函数。从那里,你应该能够做任何你需要做的事情(改变场景,发送到你的后端,等等)。请注意,这里有一个 try/catch,因为如果您尝试从 Google 登录页面获取信息,将会出现错误。

    文件如下:

    mergeInto(LibraryManager.library, {
      OpenOAuthInExternalTab: function (url, callback) {
        var urlString = Pointer_stringify(url);
        var callbackString = Pointer_stringify(callback);
    
        var child = window.open(urlString, "_blank");
        var interval = setInterval(function() {
            try {
                // When redirected back to redirect_uri
                if (child.location.hostname === location.hostname) {
                    clearInterval(interval) // Stop Interval
                    
                    // // Auth Code Flow -- Not used due to relative complexity
                    // const urlParams = new URLSearchParams(child.location.search);
                    // const authCode = urlParams.get('code');
                    // console.log("Auth Code: " + authCode.toString());
                    // console.log("Callback: " + callbackString);
                    // window.unityInstance.SendMessage('Auth', callbackString, authCode);
    
                    // Implicit Flow
                    var fragmentString = child.location.hash.substr(1);
                    var fragment = {};
                    var fragmentItemStrings = fragmentString.split('&');
                    for (var i in fragmentItemStrings) {
                        var fragmentItem = fragmentItemStrings[i].split('=');
                        if (fragmentItem.length !== 2) {
                            continue;
                        }
                        fragment[fragmentItem[0]] = fragmentItem[1];
                    }
                    var accessToken = fragment['access_token'] || '';
                    console.log("access_token: " + accessToken);
                    child.close();
    
                    // Invoke callback function
                    window.unityInstance.SendMessage('Auth', callbackString, accessToken);l
                }
            }
            catch(e) {
                // Child window in another domain
                console.log("Still logging in ...");
            }
        }, 50);
      }
    });
    

    然后,在我的 C# 脚本中,我使用以下代码调用此函数:

    public class GoogleHelper : MonoBehaviour
    {   
        [DllImport("__Internal")]
        private static extern void OpenOAuthInExternalTab(string url, string callbackFunctionName);
        // ...
    
        public void Login(string callbackFunctionName) {
            var redirectUri = "https://localhost";
            var url = "https://accounts.google.com/o/oauth2/v2/auth"
                    + $"?client_id={clientId}"
                    + "&response_type=token"
                    + "&scope=openid%20email%20profile"
                    + $"&redirect_uri={redirectUri}";
            OpenOAuthInExternalTab(url, callbackFunctionName);
        }
        // ...
    }
    
    
    

    当然,这是超级hacky,而且我对Javascript不是很熟悉,所以不太了解上面代码的含义,但它适用于我的用例。

    【讨论】: