【问题标题】:Authentication with Google in Web API and Swagger在 Web API 和 Swagger 中使用 Google 进行身份验证
【发布时间】:2020-07-26 08:56:12
【问题描述】:

我已将 Web API c# 应用程序与 Swagger 集成。我已经实现了工作正常的 AAD 身份验证。现在我想添加谷歌身份验证。我已经完成了如下代码。

SwaggerConfig.cs

 c.OAuth2("oauth2")
       .Description("Google Auth")
       .Flow("implicit")
       .AuthorizationUrl($"https://accounts.google.com/o/oauth2/v2/auth")
       .Scopes(scopes => scopes.Add("openid", "Sign you in permission"));

Startup.cs

app.UseExternalSignInCookie(Microsoft.AspNet.Identity.DefaultAuthenticationTypes.ExternalCookie);
googleAuthOptions = new GoogleOAuth2AuthenticationOptions()
{
            ClientId = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com",
            ClientSecret = "xxxxxxxxxxxxxxxxxxxx",

};
app.UseGoogleAuthentication(googleAuthOptions);

我从谷歌登录屏幕获得授权并成功重定向回用户界面。但是当我尝试访问任何方法时,我得到 401 Unauthorized 错误,即使不记名令牌存在。
After authenticating with google

我知道我没有验证 Startup.cs 文件中的访问令牌,因为我缺乏相关知识。我已经阅读了几篇具有复杂实现的文章,但我想以最简单的方式实现这一目标。以下代码适用于 AAD,无需任何进一步的代码验证。

app.UseWindowsAzureActiveDirectoryBearerAuthentication(
                new Microsoft.Owin.Security.ActiveDirectory.WindowsAzureActiveDirectoryBearerAuthenticationOptions
                {
                    Tenant = Settings.AzureADTenant,
                    TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
                    {
                        ValidAudiences = new string[] { Settings.AzureADAudience, Settings.AzureAppURI },
                        ValidIssuers = new string[] {
                            $"https://sts.windows.net/{Settings.AzureADTenant}/",
                            $"https://login.microsoftonline.com/{Settings.AzureADTenant}/v2.0"
                        }
                    }
                });

【问题讨论】:

    标签: c# asp.net-web-api oauth-2.0 swagger google-oauth


    【解决方案1】:

    您获得的令牌是访问令牌,问题是默认情况下,swagger 使用 response_type 参数作为令牌而不是令牌 id_token 发出令牌请求。

    您可以按照以下步骤从 swagger 向 google 进行身份验证:

    1. 在你的wwwroot文件夹中(如果没有,可以创建),创建一个js文件,内容如下

      window.swaggerUiAuth = window.swaggerUiAuth || {};
      window.swaggerUiAuth.tokenName = 'id_token';
      if (!window.isOpenReplaced) {
          window.open = function (open) {
              return function (url) {
                  url = url.replace('response_type=token', 'response_type=token id_token');
                  return open.call(window, url);
              };
          }(window.open);
          window.isOpenReplaced = true;
      }
      
    2. 完成后,在您的 Configure 方法中添加以下内容:

      app.UseSwaggerUI(c =>
      {
          //your additional stuff...
          c.OAuthAdditionalQueryStringParams(new Dictionary<string, string> {{ "nonce", "anyNonceStringHere" }});
          c.OAuthClientId(this.oauth2Config.ClientId);
          c.InjectJavascript("YourJustCreatedJSFileName.js");
      });
      
    3. 现在在您的 AddSwaggerGen 构建器中,添加安全定义和安全要求。 (您可以将其拆分为多个方法以使其更简洁)。

      //in your ConfigureServices 
      services.AddSwaggerGen(c =>
      {
          c.SwaggerDoc("v1", new OpenApiInfo { Title = "wellship_svc_app", Version = "v1" });
          this.AddSwaggerOAuth2Configuration(c);
      }); 
      

    在你的启动类中创建这个私有方法。请注意使用 id_token 而不是访问令牌的安全方案中的扩展属性。

    private void AddSwaggerOAuth2Configuration(SwaggerGenOptions swaggerGenOptions) 
    {
        
        var securityScheme = new OpenApiSecurityScheme
        {
            Name = "Authorization",
            In = ParameterLocation.Header,
            Type = SecuritySchemeType.OAuth2,
            Flows = new OpenApiOAuthFlows()
            {
                Implicit = new OpenApiOAuthFlow()
                {
                    AuthorizationUrl = new Uri("https://accounts.google.com/o/oauth2/v2/auth"),
                    Scopes = new Dictionary<string, string> {{"email", "email"}, {"profile", "profile"}}
                }
            },
            Extensions = new Dictionary<string, IOpenApiExtension>
            {
                {"x-tokenName", new OpenApiString("id_token")}
            },
        };
            
        swaggerGenOptions.AddSecurityDefinition("Bearer", securityScheme) ;
    
        var securityRequirements = new OpenApiSecurityRequirement 
        {
            {
                new OpenApiSecurityScheme 
                { 
                    Reference = new OpenApiReference 
                    { 
                        Type = ReferenceType.SecurityScheme,
                        Id = "Bearer" 
                    } 
                },
                new List<string> {"email", "profile"}
            } 
        };
    
        swaggerGenOptions.AddSecurityRequirement(securityRequirements);
    }
    
    1. 创建一个谷歌令牌验证器类:
    public class GoogleTokenValidator : ISecurityTokenValidator
    {
        private readonly JwtSecurityTokenHandler _tokenHandler;
    
        public GoogleTokenValidator()
        {
            _tokenHandler = new JwtSecurityTokenHandler();
        }
    
        public bool CanValidateToken => true;
    
        public int MaximumTokenSizeInBytes { get; set; } = TokenValidationParameters.DefaultMaximumTokenSizeInBytes;
    
        public bool CanReadToken(string securityToken)
        {
            return _tokenHandler.CanReadToken(securityToken);
        }
    
        public ClaimsPrincipal ValidateToken(string securityToken, TokenValidationParameters validationParameters, out SecurityToken validatedToken)
        {
            validatedToken = null;
            var payload = GoogleJsonWebSignature.ValidateAsync(securityToken, new GoogleJsonWebSignature.ValidationSettings()).Result;
    
            var claims = new List<Claim>
            {
                new(ClaimTypes.NameIdentifier, payload.Name),
                new (ClaimTypes.Name, payload.Name),
                new (JwtRegisteredClaimNames.FamilyName, payload.FamilyName),
                new (JwtRegisteredClaimNames.GivenName, payload.GivenName),
                new (JwtRegisteredClaimNames.Email, payload.Email),
                new (JwtRegisteredClaimNames.Sub, payload.Subject),
                new (JwtRegisteredClaimNames.Iss, payload.Issuer)
            };
    
            try
            {
                var principle = new ClaimsPrincipal();
                principle.AddIdentity(new ClaimsIdentity(claims, JwtBearerDefaults.AuthenticationScheme));
                return principle;
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                throw;
    
            }
        }
    }
    
    1. 使用您的自定义 google 验证器类验证您的令牌:
    services.AddAuthentication(options =>
    {
        options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
        options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; 
    
    })
    .AddJwtBearer(o =>
    {
        o.IncludeErrorDetails = true;
        o.SecurityTokenValidators.Clear();
        o.SecurityTokenValidators.Add(new GoogleTokenValidator());
    });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-29
      • 2021-10-05
      • 2012-09-29
      • 2019-07-21
      • 2014-07-31
      相关资源
      最近更新 更多