ScA*_*er2 15 c# basic-authentication dotnet-httpclient
我正在尝试在 c# .net core 中实现一个 rest 客户端,它需要首先进行基本身份验证,然后在后续请求中利用一个 Bearer 令牌。
当我尝试将基本身份验证与带有 FormUrlEncodedContent 对象的 client.PostAsync 结合使用时,出现异常:
System.InvalidOperationException occurred in System.Net.Http.dll: 'Misused header name. Make sure request headers are used with HttpRequestMessage, response headers with HttpResponseMessage, and content headers with HttpContent objects.'
Run Code Online (Sandbox Code Playgroud)
//setup reusable http client
HttpClient client = new HttpClient();
Uri baseUri = new Uri(url);
client.BaseAddress = baseUri;
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.ConnectionClose = true;
//Post body content
var values = new List<KeyValuePair<string,string>>();
values.Add(new KeyValuePair<string, string>("grant_type", "client_credentials"));
var content = new FormUrlEncodedContent(values);
//Basic Authentication
var authenticationString = $"{clientId}:{clientSecret}";
var base64EncodedAuthenticationString = Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(authenticationString));
content.Headers.Add("Authorization", $"Basic {base64EncodedAuthenticationString}");
//make the request
var task = client.PostAsync("/oauth2/token",content);
var response = task.Result;
response.EnsureSuccessStatusCode();
string responseBody = response.Content.ReadAsStringAsync().Result;
Console.WriteLine(responseBody);
Run Code Online (Sandbox Code Playgroud)
Exception has occurred: CLR/System.InvalidOperationException
An unhandled exception of type 'System.InvalidOperationException' occurred in System.Net.Http.dll: 'Misused header name. Make sure request headers are used with HttpRequestMessage, response headers with HttpResponseMessage, and content headers with HttpContent objects.'
at System.Net.Http.Headers.HttpHeaders.GetHeaderDescriptor(String name)
at System.Net.Http.Headers.HttpHeaders.Add(String name, String value)
Run Code Online (Sandbox Code Playgroud)
Paw*_*aga 36
从调用代码显式创建 HttpClient 并不是一个好习惯。请使用HttpClientFactory来简化很多事情。
但是,如果您想使用基本身份验证,只需创建HttpRequestMessage并添加以下标头:
var request = new HttpRequestMessage(HttpMethod.Post, getPath)
{
Content = new FormUrlEncodedContent(values)
};
request.Headers.Authorization = new BasicAuthenticationHeaderValue("username", "password");
// other settings
Run Code Online (Sandbox Code Playgroud)
如果您决定使用推荐的 IHttpClientFactory,那就更简单了:
serviceCollection.AddHttpClient(c =>
{
c.BaseAddress = new Uri("your base url");
c.SetBasicAuthentication("username", "password");
})
Run Code Online (Sandbox Code Playgroud)
ScA*_*er2 22
看起来您不能使用 PostAsync 并且可以访问用于身份验证的标题。我不得不使用 HttpRequestMessage 和 SendAsync。
//setup reusable http client
HttpClient client = new HttpClient();
Uri baseUri = new Uri(url);
client.BaseAddress = baseUri;
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.ConnectionClose = true;
//Post body content
var values = new List<KeyValuePair<string, string>>();
values.Add(new KeyValuePair<string, string>("grant_type", "client_credentials"));
var content = new FormUrlEncodedContent(values);
var authenticationString = $"{clientId}:{clientSecret}";
var base64EncodedAuthenticationString = Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(authenticationString));
var requestMessage = new HttpRequestMessage(HttpMethod.Post, "/oauth2/token");
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Basic", base64EncodedAuthenticationString);
requestMessage.Content = content;
//make the request
var task = client.SendAsync(requestMessage);
var response = task.Result;
response.EnsureSuccessStatusCode();
string responseBody = response.Content.ReadAsStringAsync().Result;
Console.WriteLine(responseBody);
Run Code Online (Sandbox Code Playgroud)
Nei*_*oss 12
不要编码整个身份验证字符串 - 编码“用户名:密码”表达式并将结果附加到“基本”前缀。
var authenticationString = $"{clientId}:{clientSecret}";
var base64EncodedAuthenticationString = Convert.ToBase64String(System.Text.ASCIIEncoding.UTF8.GetBytes(authenticationString));
content.Headers.Add("Authorization", "Basic " + base64EncodedAuthenticationString);
Run Code Online (Sandbox Code Playgroud)
此外,请考虑仅使用 ASCII 编码 - 服务器可能无法理解 UTF8,除非您charset向标头添加声明。
维基百科似乎很好地涵盖了这一点。
具体问题是这一行(如下)
content.Headers.Add("Authorization", $"Basic {base64EncodedAuthenticationString}");
Run Code Online (Sandbox Code Playgroud)
这会失败,因为HttpContent.Headers( System.Net.Http.Headers.HttpContentHeaders) 仅适用于特定于内容的标头,例如Content-Type、Content-Length等。
你已经声明你不能使用它DefaultRequestHeaders,因为你只需要它用于一个请求 - 但你也不能使用它PostAsync- 只有SendAsync你自己构建HttpRequestMessage,根据你自己的答案 和@NeilMoss的答案- 但你将来可以使用扩展方法。
但为了其他读者的利益,另一种选择是在现有的基础上添加一个新的扩展方法PostAsync,这实际上非常简单(只有 3 行!):
public Task<HttpResponseMessage> PostAsync( this HttpClient httpClient, Uri requestUri, HttpContent content, String basicUserName, String basicPassword, String? challengeCharSet = null, CancellationToken cancellationToken = default )
{
if( basicUserName.IndexOf(':') > -1 ) throw new ArgumentException( message: "RFC 7617 states that usernames cannot contain colons.", paramName: nameof(basicUserName) );
HttpRequestMessage httpRequestMessage = new HttpRequestMessage( HttpMethod.Post, requestUri );
httpRequestMessage.Content = content;
//
Encoding encoding = Encoding.ASCII;
if( challengeCharSet != null )
{
try
{
encoding = Encoding.GetEncoding( challengeCharSet );
}
catch
{
encoding = Encoding.ASCII;
}
}
httpRequestMessage.Headers.Authorization = new AuthenticationHeaderValue(
scheme : "Basic",
parameter: Convert.ToBase64String( encoding.GetBytes( userName + ":" + password ) )
);
return SendAsync( httpRequestMessage, cancellationToken );
}
Run Code Online (Sandbox Code Playgroud)
用法:
HttpClient httpClient = ...
using( HttpResponseMessage response = await httpClient.PostAsync( uri, content, basicUserName: "AzureDiamond", basicPassword: "hunter2" ).ConfigureAwait(false) )
{
// ...
}
Run Code Online (Sandbox Code Playgroud)
使用 .NET 6,我使用该HttpClient.DefaultRequestHeaders.Authorization属性来设置授权标头。
// This example will send a signing request to the RightSignature API
var api = "https://api.rightsignature.com/public/v2/sending_requests";
// requestJson is the serialized JSON request body
var contentData = new StringContent(requestJson, Encoding.UTF8, "application/json");
// Instantiate client (for testing), use Microsoft's guidelines in production
var client = new HttpClient();
// Use basic auth, the token has already been converted to base64
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", tokenB64);
try
{
var response = await client.PostAsync(api, contentData);
}
...
Run Code Online (Sandbox Code Playgroud)
祝你好运!
| 归档时间: |
|
| 查看次数: |
26929 次 |
| 最近记录: |