You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET Core 7中gRPC服务的认证授权实现方案咨询

在ASP.NET Core 7中实现gRPC服务的JWT认证授权

一、核心思路

无需手动维护令牌-用户ID字典,直接依托ASP.NET Core的JWT认证中间件,结合gRPC的上下文/拦截器完成认证,同时在业务方法中安全获取用户标识(如客户端ID)来筛选数据。

二、第一步:配置ASP.NET Core的JWT认证

在Program.cs中配置JWT认证服务与gRPC托管:

var builder = WebApplication.CreateBuilder(args);

// 注册JWT认证
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = builder.Configuration["Jwt:Issuer"],
            ValidAudience = builder.Configuration["Jwt:Audience"],
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"]))
        };
        // 适配gRPC的Authorization头部传递逻辑
        options.Events = new JwtBearerEvents
        {
            OnMessageReceived = context =>
            {
                var token = context.Request.Headers.Authorization.FirstOrDefault()?.Split(" ").Last();
                if (!string.IsNullOrEmpty(token))
                {
                    context.Token = token;
                }
                return Task.CompletedTask;
            }
        };
    });

builder.Services.AddAuthorization();
// 注册gRPC服务
builder.Services.AddGrpc();

var app = builder.Build();

// 启用认证、授权中间件
app.UseAuthentication();
app.UseAuthorization();

// 映射gRPC服务
app.MapGrpcService<MyBankService>();
app.MapGrpcService<AuthService>();

app.Run();

三、第二步:实现登录接口生成JWT令牌

创建专门的gRPC认证服务,验证用户凭证后生成包含客户端ID的JWT返回给客户端,无需手动维护令牌映射:

public class AuthService : AuthServiceBase // 对应gRPC定义的Auth服务契约
{
    private readonly IConfiguration _config;
    private readonly IClientRepository _clientRepository;

    public AuthService(IConfiguration config, IClientRepository clientRepository)
    {
        _config = config;
        _clientRepository = clientRepository;
    }

    public override async Task<LoginResponse> Login(LoginRequest request, ServerCallContext context)
    {
        // 验证用户名与密码
        var client = await _clientRepository.GetClient(request.Username);
        if (client == null || !BCrypt.Net.BCrypt.Verify(request.Password, client.HashedPassword))
        {
            throw new RpcException(new Status(StatusCode.Unauthenticated, "用户名或密码错误"));
        }

        // 生成嵌入客户端ID的JWT令牌
        var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:Key"]));
        var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);

        var claims = new[]
        {
            new Claim(ClaimTypes.NameIdentifier, client.Id.ToString()),
            new Claim(ClaimTypes.Name, client.Username)
        };

        var token = new JwtSecurityToken(
            issuer: _config["Jwt:Issuer"],
            audience: _config["Jwt:Audience"],
            claims: claims,
            expires: DateTime.Now.AddMinutes(30),
            signingCredentials: credentials);

        return new LoginResponse
        {
            Token = new JwtSecurityTokenHandler().WriteToken(token)
        };
    }
}

四、第三步:在gRPC业务服务中获取客户端ID

直接从ServerCallContext的HTTP上下文里提取已认证用户的Claim信息,无需手动处理令牌验证:

public class MyBankService : BankServiceBase // 对应gRPC定义的Bank服务契约
{
    private readonly IApplicationService _applicationService;

    public MyBankService(IApplicationService applicationService)
    {
        _applicationService = applicationService;
    }

    public override async Task<BankAccountResponse> GetBankAccountOfClient(EmptyRequest request, ServerCallContext context)
    {
        // 从认证上下文提取客户端ID
        var clientIdClaim = context.GetHttpContext().User.FindFirst(ClaimTypes.NameIdentifier);
        if (clientIdClaim == null || !long.TryParse(clientIdClaim.Value, out long clientId))
        {
            throw new RpcException(new Status(StatusCode.Unauthenticated, "未获取到有效用户信息"));
        }

        // 调用应用层获取用户专属数据
        var account = await _applicationService.GetBankAccountOfClient(clientId);
        
        // 仅返回非敏感数据
        return new BankAccountResponse
        {
            AccountId = account.Id,
            Balance = account.Balance,
            AccountType = account.Type.ToString()
        };
    }
}

五、可选:用gRPC拦截器统一处理认证校验

如果需要对所有gRPC方法统一做认证/权限检查,可实现拦截器:

public class AuthInterceptor : Interceptor
{
    private readonly IAuthorizationService _authorizationService;

    public AuthInterceptor(IAuthorizationService authorizationService)
    {
        _authorizationService = authorizationService;
    }

    public override async Task<TResponse> UnaryServerHandler<TRequest, TResponse>(
        TRequest request,
        ServerCallContext context,
        UnaryServerMethod<TRequest, TResponse> continuation)
    {
        // 检查用户是否已认证
        if (!context.GetHttpContext().User.Identity.IsAuthenticated)
        {
            throw new RpcException(new Status(StatusCode.Unauthenticated, "用户未完成认证"));
        }

        // 可选:检查用户是否具备指定权限
        var authResult = await _authorizationService.AuthorizeAsync(context.GetHttpContext().User, null, "BankAccessPolicy");
        if (!authResult.Succeeded)
        {
            throw new RpcException(new Status(StatusCode.PermissionDenied, "无访问权限"));
        }

        return await continuation(request, context);
    }
}

在Program.cs中注册拦截器:

builder.Services.AddGrpc(options =>
{
    options.Interceptors.Add<AuthInterceptor>();
});

方案优势

  • 无需手动维护令牌字典:JWT自身包含用户标识与过期信息,由ASP.NET Core自动验证有效性,过期后自动失效
  • 安全可控:JWT签名机制确保令牌无法篡改,认证逻辑与业务逻辑解耦
  • 符合架构分层:ASP.NET Core负责认证校验,gRPC服务专注业务实现,避免敏感数据泄露

内容的提问来源于stack exchange,提问作者Álvaro García

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 22:12:17