如何从IdentityServer4或Cookie获取AccessToken并在MVC客户端发送至API
获取AccessToken并在HttpClient中使用的方案
嘿,我来帮你搞定这个问题!你的MVC客户端基于IdentityServer4+Cookie认证,要给API请求附加AccessToken,这里有两种实用的方法,推荐优先用第一种框架原生的方式:
方法一:使用ASP.NET Core的IAccessTokenProvider(推荐)
ASP.NET Core针对OIDC客户端场景提供了IAccessTokenProvider接口,可以直接获取有效的AccessToken,还会自动处理令牌刷新,非常省心。
步骤1:确认OIDC配置
首先确保你的Startup/Program.cs里的OIDC配置已经开启了SaveTokens,这是保存令牌到Cookie的关键:
services.AddAuthentication(options => { options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme; }) .AddCookie() .AddOpenIdConnect(options => { options.Authority = "https://your-identityserver-url"; options.ClientId = "your-mvc-client-id"; options.ClientSecret = "your-client-secret"; options.ResponseType = "code"; options.Scope.Add("your-api-scope"); // 必须包含API所需的权限范围 options.SaveTokens = true; // 开启后,令牌会被保存到Cookie的认证票据中 });
步骤2:注入服务并获取令牌
在你的HttpClient所属的服务类中,注入IAccessTokenProvider和IHttpContextAccessor,然后修改你的方法:
private readonly HttpClient _httpClient; private readonly IAccessTokenProvider _tokenProvider; private readonly IHttpContextAccessor _httpContextAccessor; // 构造函数注入依赖 public YourMenuService(HttpClient httpClient, IAccessTokenProvider tokenProvider, IHttpContextAccessor httpContextAccessor) { _httpClient = httpClient; _tokenProvider = tokenProvider; _httpContextAccessor = httpContextAccessor; } public async Task<IList<MenuModel>> GetMenusNavAsync() { // 请求AccessToken,指定需要的API权限范围 var tokenResult = await _tokenProvider.RequestAccessToken(new AccessTokenRequestOptions { Scopes = new[] { "your-api-scope" }, HttpContext = _httpContextAccessor.HttpContext }); // 校验令牌获取结果 if (!tokenResult.TryGetToken(out var accessToken)) { // 令牌获取失败,可触发认证挑战或抛出异常 await _httpContextAccessor.HttpContext.ChallengeAsync(OpenIdConnectDefaults.AuthenticationScheme); return null; } // 将令牌附加到请求头 _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken.Value); var response = await _httpClient.GetAsync("api/Menu/GetMenusNavBar"); response.EnsureSuccessStatusCode(); using var responseContent = await response.Content.ReadAsStreamAsync(); return await JsonSerializer.DeserializeAsync<List<MenuModel>>(responseContent); }
方法二:从Cookie认证票据中直接提取(不推荐)
如果不想用框架原生的令牌管理,也可以直接从当前用户的认证票据中提取AccessToken,但这种方式不会自动处理令牌刷新,需要手动维护过期逻辑:
public async Task<IList<MenuModel>> GetMenusNavAsync(IHttpContextAccessor httpContextAccessor) { var httpContext = httpContextAccessor.HttpContext; if (httpContext == null) { throw new InvalidOperationException("无法获取HttpContext"); } // 从认证票据的声明中提取AccessToken var accessToken = httpContext.User.FindFirst("access_token")?.Value; if (string.IsNullOrEmpty(accessToken)) { // 令牌不存在,触发认证挑战 await httpContext.ChallengeAsync(OpenIdConnectDefaults.AuthenticationScheme); return null; } // 附加到请求头 _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); var response = await _httpClient.GetAsync("api/Menu/GetMenusNavBar"); response.EnsureSuccessStatusCode(); using var responseContent = await response.Content.ReadAsStreamAsync(); return await JsonSerializer.DeserializeAsync<List<MenuModel>>(responseContent); }
注意:这种方法同样需要OIDC配置中开启
SaveTokens = true,否则认证票据里不会包含AccessToken。
关键提醒
- 务必确认OIDC配置的
Scope包含API所需的权限,否则获取到的令牌会被API拒绝。 - 优先使用第一种方法,
IAccessTokenProvider会自动处理令牌过期刷新、权限校验等场景,减少手动维护的工作量。
内容的提问来源于stack exchange,提问作者Lajith
相关产品推荐
相关产品推荐

