oauth2.0 使用AspNet Core 2.0的Google JWT身份验证

q0qdq0h2  于 12个月前  发布在  Go
关注(0)|答案(4)|浏览(140)

我正试图在我的ASP.NET Core 2. 0 Web API中集成Google身份验证,但我不知道如何让它工作。
我在Startup.cs ConfigureServices中有以下代码:

services.AddIdentity<ApplicationUser, IdentityRole>()
.AddDefaultTokenProviders();

services.AddAuthentication()
.AddGoogle(googleOptions => 
 {
     googleOptions.ClientId = Configuration["Authentication:Google:ClientId"];
     googleOptions.ClientSecret = Configuration["Authentication:Google:ClientSecret"];
});

字符串
Configure(IApplicationBuilder app, IHostingEnvironment env)中:

app.UseAuthentication();


当我导航到一个Authorized端点时,结果是一个302 Found,因为它可能重定向到某个登录端点(我从未创建过)。如何防止重定向,并让API只期望一个令牌,如果没有提供令牌,则返回一个401

kpbpu008

kpbpu0081#

经过两天的努力,以找到一个最好的答案,因为我想实现它作为一个后端API重定向前端到谷歌登录页面,它使用jwt身份验证作为默认的auth方法,并使用谷歌只为特定的方法,将工作在特定的方法,如果我想。
(Dot网7)
所以我这样配置我的program.cs:

var configuration = builder.Configuration;
//add authentication
builder.Services.AddAuthentication(options =>
{
    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(opt =>
{
    opt.SaveToken = true;
    opt.RequireHttpsMetadata = true;
    opt.TokenValidationParameters = new TokenValidationParameters()
    {
        ValidateIssuer = false,
        ValidateAudience = false,
        ValidateLifetime = true,
        ValidateIssuerSigningKey = true,
        ValidAudience = configuration["JWT:ValidAudience"],
        ValidIssuer = configuration["JWT: ValidIssuer"],
        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration["JWT:Secret"]))
    };
})
.AddGoogle(googleOptions =>
{
    googleOptions.ClientId = configuration["Authentication:Google:ClientId"];
    googleOptions.ClientSecret = configuration["Authentication:Google:ClientSecret"];
});

字符串
然后像这样配置你的appsetting:

"Authentication": {
 "Google": {
    "ClientId": "google client id from google",
    "ClientSecret": "google client secret from google",
    "CallbackPath": "/signin-google"
   }
 },
 "Jwt": {
    "ValidAudience": "http://localhost:5157/",
    "ValidIssuer": "http://localhost:5157/",
    "Secret": "your jwt secret"
  }


现在所有的api都需要jwt授权,你也可以像这样通过google授权:

[Authorize(AuthenticationSchemes = GoogleDefaults.AuthenticationScheme)]
    [HttpGet("GoogleAuth")]
    public void Get()
    {   
        // user info from google
        var x = this.User;

        // find the user info in your db if exists
        // user exist // generate jwt token

        // user doesnt exists lets create it
        // auto activate the user
        // generate jwt token

    }


Also this youtube video can help you

btxsgosb

btxsgosb2#

为子孙后代展示我的终极方法。
正如Tratcher所指出的,AddGoogle中间件实际上并不是用于JWT身份验证流的。
所以我接下来的问题是
1.我不能再依赖标准的dotnet核心JWT认证中间件了,因为我需要将Google令牌验证委托给Google库
1.没有C# google验证器被列为该页面上的外部客户端库之一。
经过进一步的挖掘,我发现JWT验证支持是使用这个类和方法添加到C#here的:Google.Apis.Auth.Task<GoogleJsonWebSignature.Payload> ValidateAsync(string jwt, GoogleJsonWebSignature.ValidationSettings validationSettings)
接下来,我需要弄清楚如何替换内置的JWT验证。
下面是我的自定义GoogleTokenValidator:

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; // 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, AuthenticationTypes.Password));
            return principle;
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
            throw;

        }
    }
}

字符串
Startup.cs中,我还需要清除默认的JWT验证,并添加我的自定义验证:

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());
                }


也许有一个更简单的方法,但这是我登陆的地方,它似乎工作正常!有额外的工作,我离开了这里简单,例如,检查是否已经有一个用户在我的用户的数据库中,匹配由谷歌提供的索赔,所以我道歉,如果上面的代码不100%的工作,因为我可能已经删除了一些不经意间。

nafvub8i

nafvub8i3#

我刚刚发布了一个NuGet package来处理Google OpenID Connect令牌的验证。
该软件包依赖于来自Microsoft.AspNetCore.Authentication.JwtBearer的Microsoft JWT验证和身份验证处理程序,并在托管域周围添加了一些验证。
它在JwtBearerOptions上包含一个公共扩展方法UseGoogle,允许您配置处理程序来验证Google OpenID Connect令牌,而无需其他依赖项:

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(jwt => jwt.UseGoogle(
        clientId: "<client-id-from-Google-API-console>",
        hostedDomain: "<optional-hosted-domain>"));

字符串
如果你想看看源代码,你可以找到它here

zyfwsgd6

zyfwsgd64#

Mikeyg36的回答很棒,最终帮助我解决了我的jwt token问题。然而,我添加了clientId,我觉得这很重要,因为你不想验证任何进来的id token。我还在AddIdentity中添加了“JwtBearer.AuthenticationScheme”。

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using Google.Apis.Auth;

namespace Some.Namespace
{
    public class GoogleTokenValidator : ISecurityTokenValidator
    {
        private readonly string _clientId;
        private readonly JwtSecurityTokenHandler _tokenHandler;

        public GoogleTokenValidator(string clientId)
        {
            _clientId = clientId;
            _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;
            try {
                var payload = GoogleJsonWebSignature.ValidateAsync(securityToken, new GoogleJsonWebSignature.ValidationSettings() { Audience =  new[] { _clientId }}).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),
                    };

                var principle = new ClaimsPrincipal();
                principle.AddIdentity(new ClaimsIdentity(claims, JwtBearerDefaults.AuthenticationScheme));
                return principle;
            }
            catch (Exception e)
            {
                Debug.WriteLine(e);
                throw;
            }
        }
    }
}

字符串

相关问题