Google OpenId Connect迁移:在ASP.NET应用中获取openid_id

时间:2014-11-04 08:25:05

标签: asp.net google-oauth dotnetopenauth google-openid

我已经浏览了大量的Google文档和SO Q / A,但没有运气。我想知道是否还有人按照谷歌的建议成功使用OpenId进行OpenId Connect迁移。

这就是我们过去做的事情:

IAuthenticationResponse response = _openid.GetResponse();
if (response != null) {
   //omitted for brevity       
} else {
   IAuthenticationRequest req = _openid.CreateRequest("https://www.google.com/accounts/o8/id");
   req.AddExtension(new ClaimsRequest
                    {
                        Country = DemandLevel.Request,
                        Email = DemandLevel.Request,
                        Gender = DemandLevel.Require,
                        PostalCode = DemandLevel.Require,
                        TimeZone = DemandLevel.Require
                    });
   req.RedirectToProvider();
}

这是使用可追溯到几年的DotNetOpenAuth版本完成的。由于Google已弃用OpenId身份验证,因此我们正在尝试迁移到OpenID Connect。这里的关键问题是:我能以某种方式使用最新版本的DotNetOpenAuth库或任何其他方式获取OpenId标识符(以https://www.google.com/accounts/o8/id?id=xyz的形式)吗?

我已经尝试了最新的DotNetOpenAuth,我可以让它工作,但它给了我一个新的Id(这是预期的)。我也尝试使用这个URL的Javascript方式(换行符的换行符):

https://accounts.google.com/o/oauth2/auth?
    scope=openid%20profile%20email
    &openid.realm=http://localhost/palkkac/
    &client_id=//here is the client id I created in google developer console
    &redirect_uri=http://localhost/palkkac/someaspxpagehere
    &response_type=id_token%20token

我检查了(使用Fiddler)我们当前使用旧的DotNetOpenAuth代码发送的领域值,它是http://localhost/palkkac/。我把相同的域放在上面的url中。重定向网址以领域值开始,但不完全相同。

当我重定向到一个解析id_token并解密它的简单页面时(使用https://www.googleapis.com/oauth2/v1/tokeninfo?id_token=zyx端点),我得到了这个:

audience    "client id is here"
email   "mikkark@gmail.com"
expires_in  3597
issued_at   //some numbers here
issued_to   "client id is here"
issuer  "accounts.google.com"
user_id     "here is a sequence of numbers, my id in the OpenID Connect format that is"
verified_email  true

所以没有你期望在这里找到的openid_id字段的迹象,尽管消息的整个结构似乎与Google文档不同,例如,没有标题为sub的字段。我想知道我是否真的使用了错误的端点,参数或什么?

我一直在阅读的是迁移指南:https://developers.google.com/accounts/docs/OpenID。我跳过了第2步,因为它似乎是一个可选步骤。在第3步中讨论了openid_id字段,我希望首先将其作为概念验证。

我们在Google上注册了该应用,以便创建客户端ID等。现在还有许多允许的重定向网址以及Google开发者控制台中列出的javascript来源。请告诉我,如果这些可能会搞乱系统,我会将它们发布在此处进行审核。

旁注:我们应该将我们的应用程序移到严格防火墙的环境中,我们需要打开端口以便在服务器端执行此操作。因此,优先考虑使用客户端Javascript解决方案来访问Google并将结果重定向到服务器(除非存在其他与此相关的问题)。

关于同样的问题,关于SO还有其他资源,虽然所有这些似乎都使用服务器端的不同库来完成这项工作,似乎没有人尝试过使用Javascript:

  • 这里(https://stackoverflow.com/questions/22842475/migrating-google-openid-to-openid-connect-openid-id-does-not-match)我认为通过将领域设置为与旧的OpenId2.0流程相同来解决问题。这在我的案例中似乎不起作用。
  • 超过here openid_id字段也缺失,但此处的问题更多的是如何使用DotNetOpenAuth以外的库请求来自Google的id_token。
  • 并且在here中似乎有类似的问题让Google返回openid_id字段。

1 个答案:

答案 0 :(得分:2)

您可以使用GoogleAuthentication owin中间件。

app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions
{
    SignInAsAuthenticationType = signAs,
    AuthenticationType = "Google",
    ClientId = "xxx.apps.googleusercontent.com",
    ClientSecret = "xx",
    CallbackPath = PathString.FromUriComponent("/oauth2callback"),
    Provider = new GoogleOAuth2AuthenticationProvider
    {
        OnApplyRedirect = context =>
        {
            context.Response.Redirect(context.RedirectUri + "&openid.realm=https://mydomain.com/"); // DotNetOpenAuth by default add a trailing slash, it must be exactly the same as before
        }
    },
    BackchannelHttpHandler = new MyWebRequestHandler()
}

然后,添加一个名为MyWebRequestHandler的新类:

public class MyWebRequestHandler : WebRequestHandler
    {
        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            var httpResponse = await base.SendAsync(request, cancellationToken);
            if (request.RequestUri == new Uri("https://www.googleapis.com/plus/v1/people/me")) return httpResponse;

            var configuration = await OpenIdConnectConfigurationRetriever.GetAsync("https://accounts.google.com/.well-known/openid-configuration", cancellationToken); // read the configuration to get the signing tokens (todo should be cached or hard coded)

            // google is unclear as the openid_id is not in the access_token but in the id_token
            // as the middleware dot not expose the id_token we need to parse it again
            var jwt = httpResponse.Content.ReadAsStringAsync().Result;
            JObject response = JObject.Parse(jwt);
            string idToken = response.Value<string>((object)"id_token"); 

            JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();

            try
            {
                SecurityToken token;
                var claims = tokenHandler.ValidateToken(idToken, new TokenValidationParameters()
                {
                    ValidAudience = "xxx.apps.googleusercontent.com",
                    ValidIssuer = "accounts.google.com",
                    IssuerSigningTokens = configuration.SigningTokens
                }, out token);

                var claim = claims.FindFirst("openid_id");
                // claim.Value will contain the old openid identifier
                if (claim != null) Debug.WriteLine(claim.Value);
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.ToString());
            }
            return httpResponse;
        }
    }

如果像我一样,你发现这不是很直白,请通过提出这个问题来帮助https://katanaproject.codeplex.com/workitem/359