IdentityServer4 - 缺少来自Google

时间:2017-11-06 09:10:26

标签: c# asp.net-core google-oauth identityserver4

TLDR; 在使用IdentityServer4

的上下文中
  1. 如何从Google获取电子邮件地址和高清权限?
  2. 如何填充User.Identity.Name?
  3. 我已经完成了IdentityServer quickstarts并且有一个工作的MVC客户端与IdentityServer实例通信(如果使用错误的术语,则道歉)。我正在使用外部身份验证(Google)并且没有任何温和复杂的内容,例如本地登录/数据库等。我使用ASP.NET身份。这一切都很好。

    我可以在我的MVC应用程序中成功进行身份验证,以下代码在下面的屏幕截图中生成声明:

    @foreach (var claim in User.Claims)
    {
        <dt>@claim.Type</dt>
        <dd>@claim.Value</dd>
    }
    <dt>Identity.Name</dt>
    <dd>&nbsp;@User.Identity.Name</dd>
    
    <dt>IsAuthenticated</dt>
    <dd>@User.Identity.IsAuthenticated</dd>
    

    enter image description here

    问题:

    1. 我无法从Google检索额外的声明(正确的术语?)。特别是&#39; hd&#39;甚至&#39;电子邮件&#39; - 请注意,他们不会出现在上述屏幕截图中的声明中。如何从Google获取电子邮件地址和hd声明?我错过了什么或做错了什么?
    2. 请注意,User.Identity.Name的输出为空。为什么这样,我如何填充这个?这似乎是User.Identity的唯一属性,没有设置。
    3. 我的设置如下 - 您可以看到上面的输出:

      客户端(MVC)

      在Startup.cs中,配置服务

      JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
      
      services.AddAuthentication(options =>
      {
          options.DefaultScheme = "Cookies";
          options.DefaultChallengeScheme = "oidc";
      })
      .AddCookie("Cookies")
      .AddOpenIdConnect("oidc", options =>
      {
          options.SignInScheme = "Cookies";
          options.Authority = Configuration["App:Urls:IdentityServer"];
          options.RequireHttpsMetadata = false;
          options.Resource = "openid profile email";
          options.Scope.Add("openid");
          options.Scope.Add("profile");
          options.Scope.Add("email");
          options.Scope.Add("domain");
          options.ClientId = "ctda-web";
          options.SaveTokens = true;
          options.GetClaimsFromUserInfoEndpoint = true;
      });
      

      Identity Server

      客户定义

      // OpenID Connect implicit flow client (MVC)
      new Client
      {
          ClientId = "ctda-web",
          ClientName = "Company To Do Web App",
          AllowedGrantTypes = GrantTypes.Implicit,
          EnableLocalLogin = false,
      
          // where to redirect to after login
          RedirectUris = { "http://localhost:53996/signin-oidc" },
      
          // where to redirect to after logout
          PostLogoutRedirectUris = { "http://localhost:53996/signout-callback-oidc" },
      
          AllowedScopes = new List<string>
          {
              IdentityServerConstants.StandardScopes.OpenId,
              IdentityServerConstants.StandardScopes.Profile,
              IdentityServerConstants.StandardScopes.Email,
              "domain"
          }
      }
      

      IdentityResource定义

      return new List<IdentityResource>
      {
          new IdentityResources.OpenId(),
          new IdentityResources.Profile(),
          new IdentityResources.Email(),
          new IdentityResource
          {
              Name = "domain",
              DisplayName = "Google Organisation",
              Description = "The hosted G Suite domain of the user, if part of one",
              UserClaims = new List<string> { "hd"}
          } 
      };
      

2 个答案:

答案 0 :(得分:4)

答案非常明显:只要您具有以下配置(在Identity Server Startup.cs中),IdentityServer4提供的示例代码就可以运行:

services.AddIdentityServer()
    .AddDeveloperSigningCredential()
    .AddInMemoryApiResources(Config.GetApiResources())
    .AddInMemoryIdentityResources(Config.GetIdentityResources())
    .AddInMemoryClients(Config.GetClients()
    .AddTestUsers(Config.GetUsers()); //<--- this line here

为什么呢?因为AddTestUsers正在做一堆the plumbing,你需要在你自己的世界里做。演练隐含地假设您转移到EF或ASP.NET Identity等,并且如果您不打算使用这些数据存储,则不清楚您需要做什么。简而言之,您需要:

  1. 创建一个对象来代表用户(here's a starter
  2. 创建持久性/查询类(here's a starter
  3. 创建一个IProfileService实例,将其全部绑定在一起,放入用户和UserStore的定义(here's a starter
  4. 添加适当的绑定等
  5. 我的IdentityServer Startup.cs看起来像这样(我想故意在内存中做,但显然不使用示例中提供的测试用户):

    services.AddSingleton(new InMemoryUserStore()); //<-- new
    
    services.AddIdentityServer()
        .AddDeveloperSigningCredential()
        .AddInMemoryApiResources(Config.GetApiResources())
        .AddInMemoryIdentityResources(Config.GetIdentityResources())
        .AddInMemoryClients(Config.GetClients())
        .AddProfileService<UserProfileService>(); //<-- new
    

    原来Google确实会将电子邮件作为索赔的一部分。问题的代码示例中的范围有效。

答案 1 :(得分:0)

我可以告诉您如何收到要退回的电子邮件。

有两种方法可以执行此操作,但它们都要求您将电子邮件范围添加到初始请求中。只是发送openId不会起作用。

  

Openid电子邮件

UserInfo请求

现在,当您获得访问令牌时,您可以执行

https://www.googleapis.com/oauth2/v1/userinfo?alt=json&access_token={access token}

响应

{
  "family_name": "Lawton", 
  "name": "Linda Lawton", 
  "picture": "https://lh5.googleusercontent.com/-a1CWlFnA5xE/AAAAAAAAAAI/AAAAAAAAl1I/UcwPajZOuN4/photo.jpg", 
  "gender": "female", 
  "email": "xxxx@gmail.com", 
  "link": "https://plus.google.com/+LindaLawton", 
  "given_name": "Linda", 
  "id": "117200475532672775346", 
  "verified_email": true
}

令牌信息请求:

使用id令牌

 https://www.googleapis.com/oauth2/v3/tokeninfo?id_token={token id}

响应

{
 "azp": "07408718192.apps.googleusercontent.com",
 "aud": "07408718192.apps.googleusercontent.com",
 "sub": "00475532672775346",
 "email": "XX@gmail.com",
 "email_verified": "true",
 "at_hash": "8ON2HwraMXbPpP0Nwle8Kw",
 "iss": "https://accounts.google.com",
 "iat": "1509967160",
 "exp": "1509970760",
 "alg": "RS256",
 "kid": "d4ed62ee21d157e8a237b7db3cbd8f7aafab2e"
}

关于如何填充你的控制器,我无法帮助。