Google 登录 - “access_token” vs “id_token” vs “code”

Bur*_*alp 5 oauth google-signin

在我们的网站中,我们曾经在使用 Google Sign In 登录时使用 access_token。首先,我们将用户重定向到 google,用户将 access_token 带给我们,然后我们验证该令牌以确保用户是实际的 Google 用户。

然后,我们需要为我们的 Android 应用程序提供 Google 登录功能,因此我希望 Android 开发人员将 access_token 带给我们。他回答说不能。我搜索了一下,发现几乎没有关于 access_token 的文档。在文档中,谷歌说我使用“id_token”。

好的,我想让开发者给我带来id_token,我已经成功验证了token的完整性。然后我想为网站实现相同的功能。

我的 C# 代码是:

string googleId = GoogleJsonWebSignature.ValidateAsync(idToken).Result.Subject;
Run Code Online (Sandbox Code Playgroud)

当我在本地运行它时它工作,但是当我在生产中尝试时,它给出了一个错误:JWT尚未有效

id_token 是发送到后端并验证的正确方法吗?我也找到了另一个选择:code

代码类似于 A/12112312 ......

Access_token 类似于 ya29.somemorestring

我的问题是,发送到后端哪个正确?顺便说一句,我认为 access_token 有点过时或类似的东西。

Ben*_*let 2

是的,您应该使用 id_token。您可以使用以下命令在客户端获取 id_token:

var id_token = googleUser.getAuthResponse().id_token;
Run Code Online (Sandbox Code Playgroud)

并使用以下方法在服务器端验证它(在 try/catch 块中执行以捕获任何错误):

token = await GoogleJsonWebSignature.ValidateAsync(idToken);
Run Code Online (Sandbox Code Playgroud)

JWT尚未有效错误是由于服务器上的时间缓慢造成的。即使慢几秒也会导致这个问题。为了确保它始终有效,您需要实现一个自定义时钟,它可以从某处获取准确的时间。以下是使用 NNTP 的示例:

public class AccurateClock : Google.Apis.Util.IClock
{
    const int UpdateIntervalMinutes = 60;
    const string NntpServer = "time.nist.gov";

    private TimeSpan _timeOffset;
    private DateTime _lastChecked;

    public AccurateClock()
    {
        _timeOffset = TimeSpan.FromSeconds(0);
        _lastChecked = DateTime.MinValue;
    }

    private DateTime GetTime()
    {
        try
        {
            if (DateTime.Now.Subtract(_lastChecked).TotalMinutes >= UpdateIntervalMinutes)
            {
                // Update offset 
                var client = new TcpClient(NntpServer, 13);
                DateTime serverTime;
                using (var streamReader = new StreamReader(client.GetStream()))
                {
                    var response = streamReader.ReadToEnd();
                    var utcDateTimeString = response.Substring(7, 17);
                    serverTime = DateTime.ParseExact(utcDateTimeString, "yy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);
                }
                _timeOffset = DateTime.UtcNow.Subtract(serverTime);
                _lastChecked = DateTime.Now;
            }
            var accurateTime = DateTime.UtcNow.Subtract(_timeOffset);
            return accurateTime;
        }
        catch (Exception ex)
        {
            return DateTime.UtcNow;
        }

    }

    public DateTime Now
    {
        get
        {
            return GetTime().ToLocalTime();
        }
    }

    public DateTime UtcNow
    {
        get
        {

            return GetTime();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,您将自定义时钟传递给验证方法。

token = await GoogleJsonWebSignature.ValidateAsync(idToken, new AccurateClock());
Run Code Online (Sandbox Code Playgroud)

请注意:这将在每次创建类时更新正确时间和本地计算机时间之间的差异,因此您确实希望在您使用的任何 IOC 容器中将其注册为单例,并将引用传递给验证器。然后,它会每小时使用 NNTP 重新检查时间。如果您不使用 IOC 容器,您可以将该类设为静态。