C# 无法从托管服务中的缓存附加身份验证令牌
我是.net新手,我非常想了解应用程序的这种行为。我有一个名为C# 无法从托管服务中的缓存附加身份验证令牌,c#,.net,asp.net-core,.net-core,C#,.net,Asp.net Core,.net Core,我是.net新手,我非常想了解应用程序的这种行为。我有一个名为GetOrg()的函数,它基本上请求API端点并获取数据,以获取我需要的数据,以便在每次请求中传递Auth令牌。要获取身份验证令牌,我有另一个函数调用GetAccessToken获取令牌并将其保存在缓存中。我创建了一个名为httpclient,它将令牌附加到NonProductionEnv客户端的每个请求 现在的问题是,当我在托管服务中设置GetOrg()时,如下图所示,它没有在没有身份验证令牌的情况下附加令牌和请求API端点,但是如
GetOrg()
的函数,它基本上请求API端点并获取数据,以获取我需要的数据,以便在每次请求中传递Auth令牌。要获取身份验证令牌,我有另一个函数调用GetAccessToken
获取令牌并将其保存在缓存中。我创建了一个名为httpclient
,它将令牌附加到NonProductionEnv
客户端的每个请求
现在的问题是,当我在托管服务中设置GetOrg()
时,如下图所示,它没有在没有身份验证令牌的情况下附加令牌和请求API端点,但是如果我在控制器中设置GetOrg()
,它就可以正常工作
托管服务:
public class TokenService : DelegatingHandler, IHostedService
{
public IConfiguration Configuration { get; }
protected IMemoryCache _cache;
private Timer _timer;
public IHttpClientFactory _clientFactory;
protected HttpClient _client_NP;
private readonly IServiceScopeFactory _scopeFactory;
public TokenService(IConfiguration configuration, IMemoryCache memoryCache, IHttpClientFactory clientFactory, IServiceScopeFactory scopeFactory)
{
Configuration = configuration;
_cache = memoryCache;
_clientFactory = clientFactory;
_scopeFactory = scopeFactory;
// NamedClients foreach Env.
_client_NP = _clientFactory.CreateClient("NonProductionEnv");
}
public Task StartAsync(CancellationToken cancellationToken)
{
_timer = new Timer(GetAccessToken, null, 0, 3300000);
// Thread.Sleep(2000);
_timer = new Timer(Heartbeat, null, 1000, 1000);
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
//Timer does not have a stop.
_timer?.Change(Timeout.Infinite, 0);
return Task.CompletedTask;
}
public async Task<Token> GetToken(Uri authenticationUrl, Dictionary<string, string> authenticationCredentials)
{
HttpClient client = new HttpClient();
FormUrlEncodedContent content = new FormUrlEncodedContent(authenticationCredentials);
HttpResponseMessage response = await client.PostAsync(authenticationUrl, content);
if (response.StatusCode != System.Net.HttpStatusCode.OK)
{
string message = String.Format("POST failed. Received HTTP {0}", response.StatusCode);
throw new ApplicationException(message);
}
string responseString = await response.Content.ReadAsStringAsync();
Token token = JsonConvert.DeserializeObject<Token>(responseString);
return token;
}
private void GetAccessToken(object state)
{
Dictionary<string, string> authenticationCredentials_np = Configuration.GetSection("NonProductionEnvironment:Credentials").GetChildren().Select(x => new KeyValuePair<string, string>(x.Key, x.Value)).ToDictionary(x => x.Key, x => x.Value);
Token token_np = GetToken(new Uri(Configuration["NonProductionEnvironment:URL"]), authenticationCredentials_np).Result;
_cache.Set("np", token_np.AccessToken);
}
public void Heartbeat(object state)
{
// Discard the result
_ = GetOrg();
}
public async Task GetOrg()
{
var request = new HttpRequestMessage(HttpMethod.Get, "organizations");
var response = await _client_NP.SendAsync(request);
var json = await response.Content.ReadAsStringAsync();
OrganizationsClass.OrgsRootObject model = JsonConvert.DeserializeObject<OrganizationsClass.OrgsRootObject>(json);
using (var scope = _scopeFactory.CreateScope())
{
var _DBcontext = scope.ServiceProvider.GetRequiredService<PCFStatusContext>();
foreach (var item in model.resources)
{
var g = Guid.Parse(item.guid);
var x = _DBcontext.Organizations.FirstOrDefault(o => o.OrgGuid == g);
if (x == null)
{
_DBcontext.Organizations.Add(new Organizations
{
OrgGuid = g,
Name = item.name,
CreatedAt = item.created_at,
UpdatedAt = item.updated_at,
Timestamp = DateTime.Now,
Foundation = 3
});
}
else if (x.UpdatedAt != item.updated_at)
{
x.CreatedAt = item.created_at;
x.UpdatedAt = item.updated_at;
x.Timestamp = DateTime.Now;
}
}
await GetSpace();
await _DBcontext.SaveChangesAsync();
}
}
}
下面的日志每秒生成一次,因为我需要每秒调用api端点
正在收听:正在收听:
应用程序已启动。按Ctrl+C组合键关闭。
信息:System.Net.Http.HttpClient.NonProductionNV.LogicalHandler[100]
开始处理HTTP请求获取信息:
System.Net.Http.HttpClient.NonProductionEnv.ClientHandler[100]
发送HTTP请求获取信息:System.Net.HTTP.HttpClient.NonProductionEnv.ClientHandler[101]
53.3973ms后收到HTTP响应-未经授权
注:我对.net及其工作原理了解不多。您的
HttpClient
正在注册一个静态值,该值在应用程序启动时从缓存中检索。此时,托管服务尚未运行,所以缓存中还没有任何值。一旦缓存中最终有了一个值,标头就已经设置很久了,您永远不会重置它
在这里,缓存实际上是完全不必要的。您也不需要在实际的客户端注册中设置授权
头。相反,只需将GetAccessToken
方法修改为:
private void GetAccessToken(object state)
{
Dictionary<string, string> authenticationCredentials_np = Configuration.GetSection("NonProductionEnvironment:Credentials").GetChildren().Select(x => new KeyValuePair<string, string>(x.Key, x.Value)).ToDictionary(x => x.Key, x => x.Value);
Token token_np = GetToken(new Uri(Configuration["NonProductionEnvironment:URL"]), authenticationCredentials_np).Result;
_client_NP.DefaultRequestHeaders.Add("Authorization", $"Bearer {token_np.AccessToken}");
}
private void GetAccessToken(对象状态)
{
字典身份验证凭据\u np=Configuration.GetSection(“非生产环境:凭据”).GetChildren().Select(x=>newkeyValuePair(x.Key,x.Value)).ToDictionary(x=>x.Key,x=>x.Value);
令牌\u np=GetToken(新Uri(配置[“非生产环境:URL]”),authenticationCredentials\u np);
_client_NP.DefaultRequestHeaders.Add(“Authorization”、$“Bearer{token_NP.AccessToken}”);
}
您的HttpClient
正在注册一个静态值,该值在应用程序启动时从缓存中检索。此时,托管服务尚未运行,所以缓存中还没有任何值。一旦缓存中最终有了一个值,标头就已经设置很久了,您永远不会重置它
在这里,缓存实际上是完全不必要的。您也不需要在实际的客户端注册中设置授权
头。相反,只需将GetAccessToken
方法修改为:
private void GetAccessToken(object state)
{
Dictionary<string, string> authenticationCredentials_np = Configuration.GetSection("NonProductionEnvironment:Credentials").GetChildren().Select(x => new KeyValuePair<string, string>(x.Key, x.Value)).ToDictionary(x => x.Key, x => x.Value);
Token token_np = GetToken(new Uri(Configuration["NonProductionEnvironment:URL"]), authenticationCredentials_np).Result;
_client_NP.DefaultRequestHeaders.Add("Authorization", $"Bearer {token_np.AccessToken}");
}
private void GetAccessToken(对象状态)
{
字典身份验证凭据\u np=Configuration.GetSection(“非生产环境:凭据”).GetChildren().Select(x=>newkeyValuePair(x.Key,x.Value)).ToDictionary(x=>x.Key,x=>x.Value);
令牌\u np=GetToken(新Uri(配置[“非生产环境:URL]”),authenticationCredentials\u np);
_client_NP.DefaultRequestHeaders.Add(“Authorization”、$“Bearer{token_NP.AccessToken}”);
}
DefaultHeaders给了我一个错误“HttpClient”不包含“DefaultHeaders”的定义,并且找不到接受“HttpClient”类型的第一个参数的可访问扩展方法“DefaultHeaders”(是否缺少using指令或程序集引用?)
因此我将其替换为DefaultRequestHeaders
,它给了我未处理的异常:System.FormatException:无法添加值,因为标题“Authorization”不支持多个值。
很抱歉,它是DefaultRequestHeaders
。我将更新我的答案。程序运行,但行为奇怪有时它附加了令牌,有时不是问题所在?DefaultHeaders给了我一个错误“HttpClient”不包含“DefaultHeaders”的定义,并且没有可访问的扩展方法“DefaultHeaders”可以接受“HttpClient”类型的第一个参数找不到(是否缺少using指令或程序集引用?
因此我将其替换为DefaultRequestHeaders
,它给我的未处理异常:System.FormatException:无法添加值,因为标头“Authorization”不支持多个值。
很抱歉,它是DefaultRequestHeaders
。我会更新我的答案。程序运行,但行为很奇怪有时它附加了令牌,有时没有什么问题?