验证 Google Id 令牌 [英] Validate Google Id Token

查看:20
本文介绍了验证 Google Id 令牌的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 ASP.NET Core 为 Android 客户端提供 API.Android 作为 Google 帐户登录并将 JWT(ID 令牌)作为不记名令牌传递给 API.我的应用程序正在运行,它确实通过了身份验证检查,但我认为它没有验证令牌签名.

I'm using ASP.NET Core to serve an API to an Android client. Android signs in as a Google account and passes a JWT, the ID Token, to API as a bearer token. I have the app working, it does pass the auth checks, but I don't think it's validating the token signature.

根据 Google 的文档,我可以调用此 url 来执行此操作:https:///www.googleapis.com/oauth2/v3/tokeninfo?id_token=XYZ123,但我在服务器端找不到合适的钩子来做这件事.同样根据 Google 文档,我可以以某种方式使用客户端访问 API 来完成它,而无需每次都调用服务器.

Per Google's documents, I can call this url to do it: https://www.googleapis.com/oauth2/v3/tokeninfo?id_token=XYZ123, but I can't find the appropriate hooks on the server side to do it. Also according to the Google docs, I can somehow use the Client Access APIs to do it without calling to the server every time.

我的配置代码:

app.UseJwtBearerAuthentication( new JwtBearerOptions()
{

    Authority = "https://accounts.google.com",
    Audience = "hiddenfromyou.apps.googleusercontent.com",
    TokenValidationParameters = new TokenValidationParameters()
    {
        ValidateAudience = true,
        ValidIssuer = "accounts.google.com"
    },
    RequireHttpsMetadata = false,
    AutomaticAuthenticate = true,
    AutomaticChallenge = false,
});

如何让 JWTBearer 中间件验证签名?我几乎要放弃使用 MS 中间件并开始使用自己的中间件了.

How do I get the JWTBearer middleware to validate the signature? I'm close to giving up on using the MS middleware and rolling my own.

推荐答案

有几个不同的 方法,您可以在其中验证服务器端 ID 令牌的完整性:

There are a couple of different ways in which you can validate the integrity of the ID token on the server side:

  1. 手动" - 不断下载 Google 的公钥,验证签名,然后验证每个字段,包括 iss 一个;我在这里看到的主要优势(尽管在我看来很小)是您可以最大限度地减少发送到 Google 的请求数量.
  2. 自动" - 在 Google 的端点上执行 GET 以验证此令牌https://www.googleapis.com/oauth2/v3/tokeninfo?id_token={0}
  3. 使用 Google API 客户端库 - 如官方版.莉>
  1. "Manually" - constantly download Google's public keys, verify signature and then each and every field, including the iss one; the main advantage (albeit a small one in my opinion) I see here is that you can minimize the number of requests sent to Google.
  2. "Automatically" - do a GET on Google's endpoint to verify this token https://www.googleapis.com/oauth2/v3/tokeninfo?id_token={0}
  3. Using a Google API Client Library - like the official one.

这是第二个的样子:

private const string GoogleApiTokenInfoUrl = "https://www.googleapis.com/oauth2/v3/tokeninfo?id_token={0}";

public ProviderUserDetails GetUserDetails(string providerToken)
{
    var httpClient = new MonitoredHttpClient();
    var requestUri = new Uri(string.Format(GoogleApiTokenInfoUrl, providerToken));

    HttpResponseMessage httpResponseMessage;
    try
    {
        httpResponseMessage = httpClient.GetAsync(requestUri).Result;
    }
    catch (Exception ex)
    {
        return null;
    }

    if (httpResponseMessage.StatusCode != HttpStatusCode.OK)
    {
        return null;
    }

    var response = httpResponseMessage.Content.ReadAsStringAsync().Result;
    var googleApiTokenInfo = JsonConvert.DeserializeObject<GoogleApiTokenInfo>(response);

    if (!SupportedClientsIds.Contains(googleApiTokenInfo.aud))
    {
        Log.WarnFormat("Google API Token Info aud field ({0}) not containing the required client id", googleApiTokenInfo.aud);
        return null;
    }

    return new ProviderUserDetails
    {
        Email = googleApiTokenInfo.email,
        FirstName = googleApiTokenInfo.given_name,
        LastName = googleApiTokenInfo.family_name,
        Locale = googleApiTokenInfo.locale,
        Name = googleApiTokenInfo.name,
        ProviderUserId = googleApiTokenInfo.sub
    };
}

GoogleApiTokenInfo 类:

GoogleApiTokenInfo class:

public class GoogleApiTokenInfo
{
/// <summary>
/// The Issuer Identifier for the Issuer of the response. Always https://accounts.google.com or accounts.google.com for Google ID tokens.
/// </summary>
public string iss { get; set; }

/// <summary>
/// Access token hash. Provides validation that the access token is tied to the identity token. If the ID token is issued with an access token in the server flow, this is always
/// included. This can be used as an alternate mechanism to protect against cross-site request forgery attacks, but if you follow Step 1 and Step 3 it is not necessary to verify the 
/// access token.
/// </summary>
public string at_hash { get; set; }

/// <summary>
/// Identifies the audience that this ID token is intended for. It must be one of the OAuth 2.0 client IDs of your application.
/// </summary>
public string aud { get; set; }

/// <summary>
/// An identifier for the user, unique among all Google accounts and never reused. A Google account can have multiple emails at different points in time, but the sub value is never
/// changed. Use sub within your application as the unique-identifier key for the user.
/// </summary>
public string sub { get; set; }

/// <summary>
/// True if the user's e-mail address has been verified; otherwise false.
/// </summary>
public string email_verified { get; set; }

/// <summary>
/// The client_id of the authorized presenter. This claim is only needed when the party requesting the ID token is not the same as the audience of the ID token. This may be the
/// case at Google for hybrid apps where a web application and Android app have a different client_id but share the same project.
/// </summary>
public string azp { get; set; }

/// <summary>
/// The user's email address. This may not be unique and is not suitable for use as a primary key. Provided only if your scope included the string "email".
/// </summary>
public string email { get; set; }

/// <summary>
/// The time the ID token was issued, represented in Unix time (integer seconds).
/// </summary>
public string iat { get; set; }

/// <summary>
/// The time the ID token expires, represented in Unix time (integer seconds).
/// </summary>
public string exp { get; set; }

/// <summary>
/// The user's full name, in a displayable form. Might be provided when:
/// The request scope included the string "profile"
/// The ID token is returned from a token refresh
/// When name claims are present, you can use them to update your app's user records. Note that this claim is never guaranteed to be present.
/// </summary>
public string name { get; set; }

/// <summary>
/// The URL of the user's profile picture. Might be provided when:
/// The request scope included the string "profile"
/// The ID token is returned from a token refresh
/// When picture claims are present, you can use them to update your app's user records. Note that this claim is never guaranteed to be present.
/// </summary>
public string picture { get; set; }

public string given_name { get; set; }

public string family_name { get; set; }

public string locale { get; set; }

public string alg { get; set; }

public string kid { get; set; }
}

这篇关于验证 Google Id 令牌的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆