如何在ViewComponent或类库中为NSwag生成的客户端添加Bearer令牌
解决方案
推荐优先使用全局统一配置方案,可同时覆盖所有使用IApiClient的场景,无需每个组件单独处理令牌:
最优方案:自定义委托处理程序自动附加令牌
通过ASP.NET Core自带的DelegatingHandler拦截HttpClient请求,统一从当前上下文中读取令牌附加到请求头,一次性解决控制器、ViewComponent、自定义服务等所有场景的令牌设置问题。
步骤1:注册HttpContext访问器
在Startup.cs的配置服务方法中添加注册:
// 开启HttpContext注入访问 services.AddHttpContextAccessor();
步骤2:实现令牌附加拦截器
新建BearerTokenHandler.cs文件:
public class BearerTokenHandler : DelegatingHandler { private readonly IHttpContextAccessor _httpContextAccessor; public BearerTokenHandler(IHttpContextAccessor httpContextAccessor) { _httpContextAccessor = httpContextAccessor; } protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { // 从当前请求Cookie中读取令牌 var token = _httpContextAccessor.HttpContext?.Request.Cookies["你存储Token的Cookie名称"]; if (!string.IsNullOrWhiteSpace(token)) { request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token); } return await base.SendAsync(request, cancellationToken); } }
步骤3:修改HttpClient注册配置
修改Startup.cs中ApiClient的注册逻辑,将拦截器加入请求管道:
services.AddTransient<BearerTokenHandler>(); services.AddHttpClient<IApiClient, ApiClient>(client => { client.BaseAddress = new Uri(appSettings.Value.ApiBaseUrl); }) // 附加自定义令牌拦截器 .AddHttpMessageHandler<BearerTokenHandler>();
配置完成后,原来BaseController中OnActionExecuting里的手动设置令牌逻辑可以完全删除,所有注入IApiClient的组件都会自动附加令牌。
单场景单独解决方案
如果不需要全局配置,可针对你提出的两个问题单独处理:
1. ViewComponent中设置令牌
ViewComponent的InvokeAsync/Invoke方法执行时HttpContext已经可用,直接在方法开头设置令牌即可:
public class CustomViewComponent : ViewComponent { private readonly IApiClient _apiClient; public CustomViewComponent(IApiClient apiClient) { _apiClient = apiClient; } public async Task<IViewComponentResult> InvokeAsync() { var token = Request.Cookies["你存储Token的Cookie名称"]; if (!string.IsNullOrWhiteSpace(token)) { _apiClient.SetBearerToken(token); } // 后续业务逻辑 return View(); } }
2. 控制器构造函数中实例化自定义类库的处理
控制器构造函数执行时HttpContext还未初始化,因此无法在构造函数中直接读取Cookie,有两种处理方式:
方案A:依赖注入自定义服务(推荐)
将你的IUserService也注册到依赖注入容器中,不要手动new实例,配合上面的全局令牌配置,完全不需要手动处理令牌:
// Startup.cs中注册 services.AddScoped<IUserService, UserService>();
控制器直接注入即可:
public class TestController : BaseController { private readonly IUserService _userService; public TestController(IApiClient apiClient, IUserService userService) : base(apiClient) { _userService = userService; } }
方案B:延迟实例化自定义服务
如果一定要手动实例化UserService,将实例化逻辑移到OnActionExecuting方法中执行,此时HttpContext已经初始化完成:
public class TestController : BaseController { private IUserService _userService; public TestController(IApiClient apiClient) : base(apiClient) { } public override void OnActionExecuting(ActionExecutingContext context) { base.OnActionExecuting(context); // 首次执行时实例化服务 if (_userService == null) { _userService = new UserService(ApiClient); } } }
内容的提问来源于stack exchange,提问作者user3953989
相关产品推荐
相关产品推荐

