Unity 和 Google OAuth2 授权代码流程

Unity and Google OAuth2 Authorization Code Flow

我正在尝试构建要使用 WebGL 部署的 Unity 应用程序。我正在尝试将 Google 登录合并到应用程序中,到目前为止,这是我在 Chrome:

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

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

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

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

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

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

编辑:为了更清楚起见,我想要实现的是 FacebookSDK for Unity 在他们的 FB.LogInWithReadPermissions() 中所做的事情。整个授权代码 -> access_token 流程是无缝的,最后我被重定向回选项卡 A 中的 Unity 应用程序 access_token.

我设法找到了 Javascript 解决方案来实现我的第一个方法。区别是因为

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

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

因此,流程是从我的 C# 脚本中调用 .jslib 文件中的 Javascript 函数。基本上,该函数检测 OAuth window 何时重定向回我的 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不是很熟悉,所以真的不知道上面代码的含义,但它适用于我的用例。