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

ASP.NET Core微服务中独立认证服务的配置方法咨询(不依赖IdentityServer)

ASP.NET Core微服务中独立认证服务的配置方法咨询(不依赖IdentityServer)

嗨,我来帮你理清这个问题~你提到的那个AddJwtBearer配置确实是针对IdentityServer这类标准身份提供者(Identity Provider)的,因为Authority参数会让ASP.NET Core自动去请求该地址下的OIDC发现端点,获取JWT验证所需的密钥、发行人等元数据。如果你的认证服务只是个简单的自定义API,那这套默认配置就不适用了,得换个自定义的思路来实现。

下面我给你两种常用的方案,你可以根据自己的认证场景选择:


方案一:自定义JWT验证逻辑(适合用JWT作为凭证的场景)

如果你的认证服务是颁发JWT令牌的,只是不用IdentityServer,那可以基于JwtBearer方案做自定义扩展,关闭自动发现,自己控制验证逻辑:

using System.IdentityModel.Tokens.Jwt;
using System.Text;
using Microsoft.IdentityModel.Tokens;

services.AddAuthentication("CustomJwt")
    .AddJwtBearer("CustomJwt", options =>
    {
        // 关闭IdentityServer的自动发现机制,因为我们用自定义认证服务
        options.Authority = null;
        // 开发环境可设为false,生产环境务必开启HTTPS
        options.RequireHttpsMetadata = false;

        // 配置JWT的基础验证规则
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateLifetime = true, // 验证令牌有效期
            ValidateIssuerSigningKey = true, // 验证签名密钥
            // 如果你的JWT用对称密钥签名,这里填你的密钥(要和认证服务保持一致)
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("your-strong-secret-key-here")),
            // 如果不需要验证发行人、受众,可以设为false
            ValidateIssuer = false,
            ValidateAudience = false
        };

        // 自定义令牌验证事件,调用你的认证服务做额外校验
        options.Events = new JwtBearerEvents
        {
            OnTokenValidated = async context =>
            {
                // 从请求中获取原始JWT令牌
                var jwtToken = context.SecurityToken as JwtSecurityToken;
                if (jwtToken == null)
                {
                    context.Fail("无效的JWT令牌");
                    return;
                }

                // 调用你的独立认证服务API,验证令牌是否有效(比如是否被吊销、用户状态是否正常)
                var httpClient = context.HttpContext.RequestServices.GetRequiredService<IHttpClientFactory>().CreateClient();
                var validationResponse = await httpClient.PostAsync(
                    "https://your-auth-service/api/validate-token",
                    new StringContent(
                        System.Text.Json.JsonSerializer.Serialize(new { Token = jwtToken.RawData }),
                        Encoding.UTF8,
                        "application/json"
                    )
                );

                if (!validationResponse.IsSuccessStatusCode)
                {
                    context.Fail("认证服务验证令牌失败");
                    return;
                }

                // 从认证服务返回结果中提取用户信息,添加到当前请求的身份凭证中
                var validationResult = await validationResponse.Content.ReadFromJsonAsync<AuthValidationResult>();
                if (validationResult != null && validationResult.IsValid)
                {
                    var customClaims = new List<System.Security.Claims.Claim>
                    {
                        new System.Security.Claims.Claim(System.Security.Claims.ClaimTypes.Name, validationResult.Username),
                        new System.Security.Claims.Claim(System.Security.Claims.ClaimTypes.Role, validationResult.Role)
                    };
                    var identity = new System.Security.Claims.ClaimsIdentity(customClaims);
                    context.Principal.AddIdentity(identity);
                }
            },
            OnAuthenticationFailed = context =>
            {
                // 处理认证失败的日志或逻辑
                Console.WriteLine($"认证失败:{context.Exception.Message}");
                return Task.CompletedTask;
            }
        };
    });

// 别忘了注册HttpClientFactory,用来调用认证服务
services.AddHttpClient();

代码说明:

  • 我们自定义了一个名为CustomJwt的认证方案,避免和默认JwtBearer方案混淆
  • 关闭了Authority自动发现,自己配置JWT的签名密钥和验证规则
  • 通过OnTokenValidated事件,在基础JWT验证通过后,调用你的认证服务做二次校验(比如令牌黑名单、用户状态)
  • 可以把认证服务返回的用户信息转化为Claims,方便后续授权逻辑使用

方案二:完全自定义认证方案(适合非JWT的凭证场景)

如果你的认证用的不是JWT,而是自定义的令牌、API密钥等,那可以直接实现一个自定义的认证处理程序:

1. 定义认证选项和处理程序

using System.Security.Claims;
using System.Text.Json;
using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.Options;

// 自定义认证选项,用来配置认证服务的端点
public class CustomAuthOptions : AuthenticationSchemeOptions
{
    public string AuthServiceValidateEndpoint { get; set; }
}

// 自定义认证处理程序,核心逻辑在这里
public class CustomAuthHandler : AuthenticationHandler<CustomAuthOptions>
{
    private readonly IHttpClientFactory _httpClientFactory;

    public CustomAuthHandler(
        IOptionsMonitor<CustomAuthOptions> options,
        ILoggerFactory logger,
        UrlEncoder encoder,
        ISystemClock clock,
        IHttpClientFactory httpClientFactory)
        : base(options, logger, encoder, clock)
    {
        _httpClientFactory = httpClientFactory;
    }

    protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
    {
        // 从请求头获取认证凭证(比如Authorization: Custom your-token)
        if (!Request.Headers.TryGetValue("Authorization", out var authHeader))
        {
            // 没有凭证,返回无结果,后续可以触发挑战逻辑
            return AuthenticateResult.NoResult();
        }

        var token = authHeader.ToString().Replace("Custom ", string.Empty);
        if (string.IsNullOrEmpty(token))
        {
            return AuthenticateResult.Fail("凭证为空");
        }

        // 调用认证服务验证凭证
        var httpClient = _httpClientFactory.CreateClient();
        var response = await httpClient.PostAsync(
            Options.AuthServiceValidateEndpoint,
            new StringContent(
                JsonSerializer.Serialize(new { Token = token }),
                System.Text.Encoding.UTF8,
                "application/json"
            )
        );

        if (!response.IsSuccessStatusCode)
        {
            return AuthenticateResult.Fail("认证服务验证失败");
        }

        var validationResult = await response.Content.ReadFromJsonAsync<AuthValidationResult>();
        if (validationResult == null || !validationResult.IsValid)
        {
            return AuthenticateResult.Fail("无效的凭证");
        }

        // 创建用户身份凭证
        var claims = new List<Claim>
        {
            new Claim(ClaimTypes.NameIdentifier, validationResult.UserId),
            new Claim(ClaimTypes.Name, validationResult.Username),
            new Claim(ClaimTypes.Role, validationResult.Role)
        };
        var identity = new ClaimsIdentity(claims, Scheme.Name);
        var principal = new ClaimsPrincipal(identity);
        var ticket = new AuthenticationTicket(principal, Scheme.Name);

        return AuthenticateResult.Success(ticket);
    }
}

// 用来接收认证服务返回的验证结果
public class AuthValidationResult
{
    public bool IsValid { get; set; }
    public string UserId { get; set; }
    public string Username { get; set; }
    public string Role { get; set; }
}

2. 注册自定义认证方案

services.AddAuthentication(options =>
{
    // 设置默认的认证和挑战方案
    options.DefaultAuthenticateScheme = "CustomAuth";
    options.DefaultChallengeScheme = "CustomAuth";
})
.AddScheme<CustomAuthOptions, CustomAuthHandler>("CustomAuth", options =>
{
    // 配置你的认证服务验证端点
    options.AuthServiceValidateEndpoint = "https://your-auth-service/api/validate-token";
});

// 注册HttpClientFactory
services.AddHttpClient();

代码说明:

  • 这种方案完全自定义了认证逻辑,不管你用什么类型的凭证,都可以在HandleAuthenticateAsync方法里处理
  • 从请求头获取凭证后,调用你的认证服务做验证,验证通过后生成ClaimsPrincipal,供后续授权使用

最后要注意的点

  1. 在Startup.cs(或Program.cs)的Configure方法中,一定要确保UseAuthentication在UseAuthorization之前:
app.UseAuthentication();
app.UseAuthorization();
  1. 生产环境务必使用HTTPS,避免凭证在传输过程中被窃取
  2. 认证服务的API要做好防护,比如限流、鉴权,避免被恶意调用

备注:内容来源于stack exchange,提问作者Alseratia

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.17 08:24:35