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

问题描述:

我已经经历了大量Google文档和SO Q/A,但没有运气。我想知道是否有人已经按照Google的建议成功地使用了OpenId到OpenId Connect的迁移。Google OpenId Connect迁移:在ASP.NET应用程序中获取openid_id

这是我们用来做:

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 

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

当我重定向到一个简单的页面解析id_token和密码进行解密(使用https://www.googleapis.com/oauth2/v1/tokeninfo?id_token=zyx终点)我得到这样的:

audience "client id is here" 
email "[email protected]" 
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解决方案来访问谷歌并结合HTTPS并将结果重定向到服务器(除非有其他说法与此相反)。

上有SO对此同样问题的其他资源,尽管所有这些似乎都使用不同的库在服务器端做的工作,似乎没有人在使用Javascript作出的任何尝试:

  • 这里(https://*.com/questions/22842475/migrating-google-openid-to-openid-connect-openid-id-does-not-match)我认为通过将领域设置为与旧的OpenId2.0流程相同,解决了问题。这似乎不适用于我的情况。
  • over here openid_id字段也不存在,但这里的问题更多地是关于如何使用DotNetOpenAuth以外的库从Google请求id_token。
  • here似乎有类似的问题让谷歌返回openid_id字段。
+0

帮助我们也一直无法经过一个多月的搜索后找到解决这个问题的办法。 – spadelives 2014-11-05 20:46:55

+0

@spadelives我看到你终于想出了如何使用Owin和ASP.NET MVC发送领域参数(参考你的SO问题)。但是你仍然没有得到两个身份证,是这样吗? – mikkark 2014-11-07 06:17:56

+0

是的,我使用cortex93 – spadelives 2014-11-08 17:42:49

您可以使用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; 
     } 
    } 

如果你像我一样发现这不是真的简单,请upvoting这个问题https://katanaproject.codeplex.com/workitem/359

+0

发布的端点如果我不完全错误,这个答案是ASP.NET MVC特定的?我们的应用程序是普通的ASP.NET,尽管仍然需要应用相同的总体思路。 – mikkark 2014-11-25 14:07:56

+0

好的,这样的代码不是特定于MVC。我对OWIN不是很熟悉,所以我弄错了。我可以确认,我确实可以使用皮层代码获得旧ID。现在我想知道如何让这个Owin代码在ASP.NET(非MVC)上工作,并且与我们当前的认证机制一起“在一边”。另外,我们的应用程序是.net 4.0,所以使用Owin需要进行框架升级。 – mikkark 2014-11-27 13:07:58

+0

我设法让它在纯ASP.NET中也能正常工作。我们使用基于SAML的第三方身份验证库,这看起来有点让人头疼。我删除它后,我得到了这个工作。实际上,这可能会起作用,因为我们在不同的服务器上安装了两个安装程序,其中一个正在使用SAML,另一个将使用OAuth而不使用SAML。不过,我想让他们一起工作,至少要了解他们现在不工作。 – mikkark 2014-11-28 15:23:58