c# - Firebase - 验证 api 请求在 .net 5 中具有有效的 id token

标签 c# firebase-authentication firebase-admin .net-5 asp.net5

我正在使用来自 flutter 应用程序的 firebase 身份验证,它从前端获取 jwt,如下所示:

accessToken = await user!.getIdToken(true);

现在我想让我的 .net 5 AspNetCore 后端应用验证 ID token 。

我将 firebase admin SDK 添加到我的 .net 应用中,如下所示:

startup.cs中:

FirebaseApp.Create();

Firebase docs显示如何验证 id token :

FirebaseToken decodedToken = await FirebaseAuth.DefaultInstance
    .VerifyIdTokenAsync(idToken);
string uid = decodedToken.Uid;

但是这段代码去哪儿了?我不想为我的 AspNetCore 应用程序中的每个 Controller 端点手动执行此操作。这可以作为中间件在每次 api 请求时自动发生吗?

编辑:Eeek 我什至不认为 Firebase Admin 是我想要的。我只想以最火爆的方式验证使用 Firebase Auth for Flutter 在客户端上创建的 jwt id token 。它不适合管理员,它适合普通用户。我以为 Firebase Admin 就是这样。我该往哪个方向走?我在网上找到了各种关于不同策略的文章,所以很困惑哪一个是正确的。这够了吗? https://dominique-k.medium.com/using-firebase-jwt-tokens-in-asp-net-core-net-5-834c43d4aa00它看起来不是很火,而且似乎过于简化了?我认为下面 Dharmaraj 的回答是最火爆的方式,但我不确定 idToken 从哪里获取值(如何从请求 header 获取?否则它只是空值)。

最佳答案

我基本上遵循了this SO answer对于非 firebase 的东西和 this tutorial对于 firebase 的东西,一切正常,我可以通过 extendedContext.userResolverService 访问用户、访问 token 、声明等所有内容,并且在我所有使用 的 Web Controller 端点中验证了 id token [授权]

因为我的所有 Controller 中都有 id token ,所以我也可以从任何 Controller 手动调用它,但这不是必需的。

FirebaseToken decodedToken = await FirebaseAuth.DefaultInstance
    .VerifyIdTokenAsync(idToken);
string uid = decodedToken.Uid;

userResolverService.cs:

using System.Security.Claims;
using Microsoft.AspNetCore.Http;

public class UserResolverService
{
    public readonly IHttpContextAccessor _context;

    public UserResolverService(IHttpContextAccessor context)
    {
        _context = context;
    }

    public string GetGivenName()
    {
        return _context.HttpContext.User.FindFirst(ClaimTypes.GivenName).Value;
    }

    public string GetSurname()
    {
        return _context.HttpContext.User.FindFirst(ClaimTypes.Surname).Value;
    }

    public string GetNameIdentifier()
    {
        return _context.HttpContext.User.FindFirst(ClaimTypes.NameIdentifier).Value;
    }

    public string GetEmails()
    {
        return _context.HttpContext.User.FindFirst("emails").Value;
    }
}

扩展 DataContext(通过组合):

namespace Vepo.DataContext {
    public class ExtendedVepoContext
    {
        public VepoContext _context;
        public UserResolverService _userResolverService;

        public ExtendedVepoContext(VepoContext context, UserResolverService userService)
        {
            _context = context;
            _userResolverService = userService;
            _context._currentUserExternalId = _userResolverService.GetNameIdentifier();
        }
    }
}

启动.cs:

public void ConfigureServices(IServiceCollection services)
        {
            ....

        services.AddHttpContextAccessor();

        services.AddTransient<UserResolverService>();

        services.AddTransient<ExtendedVepoContext>();

            FirebaseApp.Create(new AppOptions()
            {
                Credential = GoogleCredential.FromFile("firebase_admin_sdk.json"),
            });

            services
                .AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                .AddJwtBearer(options =>
                {
                    options.Authority = "https://securetoken.google.com/my-firebase-app-id";
                    options.TokenValidationParameters = new TokenValidationParameters
                    {
                        ValidateIssuer = true,
                        ValidIssuer = "https://securetoken.google.com/my-firebase-app-id",
                        ValidateAudience = true,
                        ValidAudience = "my-firebase-app-id",
                        ValidateLifetime = true
                    };
                });

还有startup.cs:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env, VepoContext context, ISearchIndexService searchIndexService)
{ ....

    app.UseAuthentication();
    app.UseAuthorization();

然后像这样将 auth 添加到 Controller 端点:

[HttpPost]
[Authorize]
public async Task<ActionResult<GroceryItemGroceryStore>> PostGroceryItemGroceryStore(GroceryItemGroceryStore groceryItemGroceryStore)
{...

你可以更进一步,在每次保存时与用户一起做一些事情,比如添加元数据:

添加元数据保存的实体:

public interface IDomainEntity<TId>
{
    TId Id { get; set; }    
    DateTime SysStartTime { get; set; }
    DateTime SysEndTime { get; set; }
    string CreatedById { get; set; }
    User CreatedBy { get; set; }
    string UpdatedById { get; set; }
    User UpdatedBy { get; set; }
}

我的数据上下文:

public class VepoContext : DbContext
{
    public VepoContext(DbContextOptions<VepoContext> options)
        : base(options)
    {
    }

        public DbSet<User> User { get; set; }

        public string _currentUserExternalId;
        
        public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken))
        {
            var user = await User.SingleAsync(x => x.Id == _currentUserExternalId);

            AddCreatedByOrUpdatedBy(user);

            return (await base.SaveChangesAsync(true, cancellationToken));
        }

        public override int SaveChanges()
        {
            var user = User.Single(x => x.Id == _currentUserExternalId);

            AddCreatedByOrUpdatedBy(user);

            return base.SaveChanges();
        }

        public void AddCreatedByOrUpdatedBy(User user)
        {
            foreach (var changedEntity in ChangeTracker.Entries())
            {
                if (changedEntity.Entity is IDomainEntity<int> entity)
                {
                    switch (changedEntity.State)
                    {
                        case EntityState.Added:
                            entity.CreatedBy = user;
                            entity.UpdatedBy = user;
                            break;
                        case EntityState.Modified:
                            Entry(entity).Reference(x => x.CreatedBy).IsModified = false;
                            entity.UpdatedBy = user;
                            break;
                    }
                }
            }
        }

关于c# - Firebase - 验证 api 请求在 .net 5 中具有有效的 id token ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68094840/

相关文章:

c# - 使用 JSON 发布请求,但服务器端有 Request.Form.Count == 0

android - FirebaseAuth 为空

reactjs - 访问被阻止 : Project has not completed the google verification process

java - 我什么时候应该删除 OnCompleteListener?

python - 无法使用 python 3.72 连接 firebase

gradle - Firebase admin sdk 对 gradle 的依赖导致启动层错误

c# - 在 web api 中使用 async await 的最佳实践

c# - 如果 C# 代码是 JIT 编译的,为什么我在构建时必须在 Visual Studio 中选择一个目标平台?

c# - 关键值对的简明动态列表

firebase - 从新的 Firebase 身份验证模拟器中删除所有用户