【问题标题】:Authenticate Google JWT验证 Google JWT
【发布时间】:2018-11-08 14:08:37
【问题描述】:

我正在尝试从我的 .net 核心 webapi 应用程序验证 google jwt 不记名令牌并不断收到 401。我已经通过jwt.io 验证了令牌是有效的。我正在尝试实施此处提供的解决方案, google-jwt-authentication-with-aspnet-core-2-0

谁能看到我的代码有什么问题?

下面是我的代码:

Startup.cs

public void ConfigureServices(IServiceCollection services)
    {
        // Configure SnapshotCollector from application settings
        services.Configure<SnapshotCollectorConfiguration>(Configuration.GetSection(nameof(SnapshotCollectorConfiguration)));

        // Add SnapshotCollector telemetry processor.
        services.AddSingleton<ITelemetryProcessorFactory>(sp => new SnapshotCollectorTelemetryProcessorFactory(sp));

        conString = Microsoft
        .Extensions
        .Configuration
        .ConfigurationExtensions
        .GetConnectionString(this.Configuration, "DefaultConnection");

        services.AddDbContext<GotNextDBContext>(
            options =>
            options.UseSqlServer(conString));



        services.AddTransient<ILocationService, LocationService>();
        services.AddTransient<ICompanyService, CompanyService>();
        services.AddTransient<IUserLocationLogService, UserLocationLogService>();
        services.AddTransient<IUserService, UserService>();
        services.AddTransient<ILanguageService, LanguageService>();
        services.AddTransient<IGenderService, GenderService>();
        services.AddTransient<ISportService, SportService>();
        services.AddTransient<IMeasurementService, MeasurementService>();


        var clientIds = new List<string>();
        clientIds.Add("[myClientId]");
        services.AddAuthentication(options =>
        {
            options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;

        })
        .AddJwtBearer(o =>
        {

            o.SecurityTokenValidators.Clear();
            o.SecurityTokenValidators.Add(new GoogleTokenValidator(clientIds: clientIds ));
        });

        services.AddRouting();
        services.AddAutoMapper();

        services.AddAntiforgery(options =>
        {

            options.Cookie.Name = "X-CSRF-TOKEN-GOTNEXT-COOKIE";                
            options.HeaderName = "X-CSRF-TOKEN-GOTNEXT-HEADER";
            options.SuppressXFrameOptionsHeader = false;
        });

        var serviceProvider = services.BuildServiceProvider();

        var context = serviceProvider.GetService<GotNextDBContext>();



    }

GoogleTokenValidator.cs

public class GoogleTokenValidator : ISecurityTokenValidator
{
    private readonly JwtSecurityTokenHandler _tokenHandler;
    private readonly IEnumerable<string> _clientIds;


    public GoogleTokenValidator()
    {
        _tokenHandler = new JwtSecurityTokenHandler();
    }
    public GoogleTokenValidator(IEnumerable<string> clientIds)
    {
        _tokenHandler = new JwtSecurityTokenHandler();
        _clientIds = clientIds;

    }

    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() { Audience = _clientIds }).Result; // here is where I delegate to Google to validate

        var claims = new List<Claim>
            {
                new Claim(ClaimTypes.NameIdentifier, payload.Name),
                new Claim(ClaimTypes.Name, payload.Name),
                new Claim(JwtRegisteredClaimNames.FamilyName, payload.FamilyName),
                new Claim(JwtRegisteredClaimNames.GivenName, payload.GivenName),
                new Claim(JwtRegisteredClaimNames.Email, payload.Email),
                new Claim(JwtRegisteredClaimNames.Sub, payload.Subject),
                new Claim(JwtRegisteredClaimNames.Iss, payload.Issuer),
            };

        try
        {
            var principle = new ClaimsPrincipal();
            principle.AddIdentity(new ClaimsIdentity(claims));
            return principle;
        }
        catch (Exception e)
        {

            Console.WriteLine(e);
            throw;

        }
    }
}

}

我从 Xamarin Forms 中的 belowHttpClient 调用中访问端点。

using (var client = new HttpClient() { BaseAddress = new Uri("https://gotnext.azurewebsites.net/api/user/post/") })
            {
                client.DefaultRequestHeaders.Accept.Clear();
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                client.DefaultRequestHeaders.Add(verificationToken.tokenName, verificationToken.token);
                //client.DefaultRequestHeaders.Add("X-ZUMO-AUTH", googleUser.GoogleAuthToken);
                client.DefaultRequestHeaders.Add("Bearer", googleUser.GoogleIdToken);
                var json = JsonConvert.SerializeObject(newUser);
                var content = new StringContent(json, Encoding.UTF8, "application/json");



                response = client.PostAsync(client.BaseAddress, content).Result;

            }

【问题讨论】:

  • 只是出于兴趣,您为什么使用 Google 发布的 JWT?为什么不让 Google 验证您的用户,然后发布您自己的令牌。这是您的 API,而不是 Google。您的应用程序中是否确实需要这样做,或者您是否只认为这是基于您链接到的 SO 问题的方式?
  • @Brad 我对通过社交帐户进行身份验证还很陌生。我认为这是正确的方法。有没有更好的办法?
  • 就个人而言,我使用IdentityServer4。这是所有身份验证方法的一个很好的解决方案,并且他们有社交登录的示例。
  • @Brad 查看 IdentityServer4,它似乎是一个更简单且功能齐全的解决方案。我真的找不到任何关于如何将其添加到现有解决方案的文档。是不是就像添加一个新的 IdentityServer 项目并将端口设置为 5000 一样简单?
  • 我提供的链接是文档。它包含设置指南,并且在 Github 上有完整的解决方案示例。

标签: asp.net-core .net-core asp.net-core-mvc jwt google-authentication


【解决方案1】:

在本地单步抛出代码,这一行:return new ClaimsPrincipal(new 声明身份(声明,“谷歌”));正在返回经过身份验证的身份。然而它 仍然返回 401。我觉得我很接近了!

我也在我的网络应用程序中使用 google 进行身份验证(我从那里走了:enter link description here),我花了很多时间来调查这些。 在您的解决方案中,只需添加以下部分:

1)

//at "ConfigureServices" in "Startup.cs":
services.AddAuthorization(options =>
        {
            options.DefaultPolicy = new AuthorizationPolicyBuilder(JwtBearerDefaults.AuthenticationScheme)
                .RequireAuthenticatedUser()
                .Build();
        });

2) 上面怎么说也是需要的

return new ClaimsPrincipal(new ClaimsIdentity(claims, "Google"));

【讨论】:

  • On 2) 我相信Сергей指的是从:principal.AddIdentity(new ClaimsIdentity(claims));到 principal.AddIdentity(new ClaimsIdentity(claims, "Google"));我对我的进行了更改,并修复了 401。
【解决方案2】:

您添加到ClaimsPrincipalClaimsIdentity 没有设置AuthenticationType,因此IsAuthenticated 将始终为false (source)。

return new ClaimsPrincipal(new ClaimsIdentity(claims, "Google"));

您可以将身份验证类型设置为任何值,只要它不为空即可。

【讨论】:

  • 感谢您的快速回复。我进行了建议的更改,但仍然得到相同的结果。在查看 App Insights 时,我看到此响应消息“用户授权失败:(null)。”
  • 控制器中的[Authorize] 过滤器是什么样的?
  • 只是类的普通 [Authorize] 属性。我刚刚注意到我在经典和方法上有它。这会导致问题吗?
  • 如果它在类上,则方法上不需要它,但不会引起问题。 validatedToken = null; 行看起来不正确...我不确定在身份验证期间可能会产生什么影响。输出控制台中应该有错误指示身份验证失败的原因。
  • 步进在本地抛出代码,这一行:return new ClaimsPrincipal(new ClaimsIdentity(claims, "Google")); 正在返回一个经过身份验证的身份。但是它仍然返回 401。我觉得我很接近了!
猜你喜欢
  • 2019-11-29
  • 2021-02-09
  • 1970-01-01
  • 2019-09-13
  • 2015-06-27
  • 2019-09-05
  • 2015-08-27
  • 2021-08-14
相关资源
最近更新 更多