Godot OAuth 授权

常规开发游戏初期都不需要网络处理, 部分测试开发的时候需要用授权体系来解锁功能, 针对这部分就需要前置网络授权模块

其实这种授权方式很容易被跳过, 只是作为测试的时候上报游玩数据统计而已

这种授权机制好处就是能够构建自己的游戏社区, 能够营造类似于 Steam/WeGame 这类社区来单个账号体系多个游戏共享

而且 GitHub/Bitbucket 等平台都提供规范的 OAuth 体系用于构建应用授权体系, 方便在平台发布并且授权登陆测试游玩游戏

目前 Godot 并没有类似 WebView 之类的内部浏览器渲染功能, 所以没办法直接在游戏弹出浏览器渲染, 需要比较取巧的方法

Godot 是支持 GDNative 集成 ChromiumEmbedded 内置浏览器功能; 但还是那句话, 官方直接集成否则稳定性都不好说

OAuth 授权机制的流程如下, 这里主要对象有三个, 就是 客户端/我们自己服务端/第三方平台 :

  1. 在平台创建应用, 主流基本上需要配置并且设置好以下地址:

    • client_id: 对外公开的应用ID
    • client_secret: 自己服务器使用的验证标识, 只允许自己内部服务器使用
    • redirect_uri: 在平台配置授权完成之后的跳转回调地址
  2. 客户端拼接对应的授权连接跳转到第三方平台授权, 参数带有 client_id/redirect_uri 的 http|https 地址

  3. 用户在第三方平台授权完成之后会重定向跳转回 redirect_uri 地址, 并且在 GET 参数之中携带对应授权码 code

  4. 在客户端跳转到我们服务器 redirect_uri 地址的时候, 我们自己的服务端就需要捕获授权 code 向第三方平台验证授权是否通过

  5. 按照重定向的授权发起验证, 如果验证成功就是提示用户关闭浏览器窗口, 否则验证失败就需要将当前页面渲染成授权失败的页面

可以看到都是针对网页登陆的机制, 通过跳转第三方平台鉴权之后再跳转回我们自己服务端授权地址来二次验证,
验证成功唯一标识就可以匹配自己服务器的数据库唯一标识取出对应用户相关数据.

而唯一的问题就是 Godot 怎么获取获取到玩家数据, 这里 Godot 用 URL 直接打开外部浏览器倒是容易实现:

1
2
3
4
5
6
7
8
9
10
11
// GDScript 版本
var success = OS.shell_open('https://www.godotengine.org')
if not success:
print("打开 URL 失败!请检查系统是否允许打开浏览器")

// C# 版本
using Godot;
bool isSuccess = OS.ShellOpen('https://www.godotengine.org');
if(!isSuccess){
GD.PrintErr("打开 URL 失败!请检查系统是否允许打开浏览器");
}

需确保 URL 带 http:// 或者 https:// 前缀, 并且 Godot4 才有返回值状态

Godot的 shell_open 平台兼容性:

  • 桌面端(Windows/macOS/Linux): 完全支持

  • 移动端(Android/iOS): 需要配置权限(Android 需添加 INTERNET 权限, iOS 无需额外配置)

  • 网页端(HTML5 导出): OS.shell_open() 会直接在新标签页打开 URL

所以就需要用到取巧的方法, 这里利用 Github-OAuth 授权接口, 具体的思路如下:

  1. 客户端构建唯一的MD5哈希值提交给我们自己的服务端创建 授权会话(也可以请求服务器之后返回授权MD5值)

  2. 客户端拿到会话标识拼接成我们特殊的跳转地址 URL, 如下的特殊跳转地址

    • 第三方授权地址: https://{我们自己服务端}/github/authorize/{会话MD5值}
  3. 客户端利用 OS.shell_open 打开在外部浏览器之中, 并且游戏显示提示内容 “请在浏览器当中完成授权”

  4. 客户端提示的同时要求以 1~2s 的定时轮训确认会话是否能够拉取用户数据, 设置超时为 30s 或者直接允许用户点击取消授权

    • 会话请求地址: https://{我们自己服务端}/github/session/{会话MD5值}
  5. 客户端现在只需要按时间轮训请求获取会话状态, 后面基本都是我们自己服务端的事情

  6. 而客户端跳转到我们第三方授权地址其实会被重定向, 一般地址如下:

  7. 这里会渲染 Github 第三方平台的授权页面, 等待用户授权完成之后跳转 redirect_uri

  8. 当跳转 redirect_uri 到我们自己服务端地址的时候, 请求参数字符串携带有授权码 code, 需要在我们服务端再次验证授权

    • 拉取获取到用户授权 access_token, 通过 access_tokens 可以获取到用户在 Github 的相关对外信息, 只需要找到证明身份唯一标识
    • 授权验证地址: https://github.com/login/oauth/access_token
  9. 依靠 access_token 再次来向 Github 获取用户对外的身份信息, 内部可以获取到 UUID 等证明自己唯一标识的 ID

  10. 获取成功之后确认我们自己数据库当中是否拥有唯一标识, 如果没有就在我们数据库生成该用户数据

  11. 数据库提取用户信息并且将最开始的 授权会话MD5 和用户信息关联关联起来, 接下来客户端轮训请求将会获取到用户信息

    • 这里随着用户信息返回的还有 { token: ‘会话授权’ }, 这个会话授权就是后续上报信息/重新登陆/注销授权的关键 身份证
  12. 回到客户端这里, 现在通过会话请求地址就是正常返回用户信息, 移除会话轮训定时器并且渲染常规游戏逻辑

这样的 OAuth 授权返回的我们自己服务端 token 可以做到以下功能:

  • 日志上报(Report): 可以精准对游玩用户收集设备信息上报异常堆栈信息, 如果上报功能直接对外没有授权很容易被恶意攻击

  • 版本更新(Update): 如果内部带有热更新功能, 可以授权完成检查本地游戏资源的版本来对热更新同步到最新游戏版本

  • 反馈提交(Feedback): 用于在游戏内部追加反馈建议功能, 可以直接及时收集玩家的意见和建议

  • 社区捆绑(Community): 能够和社区要素绑定在一起, 有效加强游戏内外的交互模式

这个流程比较复杂且取巧, 大部分情况不会这样接入游戏发行平台的SDK, 不过偶尔会遇到这种 OAuth 规范授权流程需要处理