对 Web api 的 ASP.NET Core 应用程序 http 客户端请求
Posted
技术标签:
【中文标题】对 Web api 的 ASP.NET Core 应用程序 http 客户端请求【英文标题】:ASP.NET Core application http client request to a web api 【发布时间】:2021-12-23 07:52:49 【问题描述】:我有一个正在运行的 Web API,我尝试从中获取不记名令牌。从 Postman 开始的请求正在工作,我取回了令牌。从我的应用程序执行后,我总是会收到 http 400 Bad Request 错误。
我在这里错过了什么?
public async Task<string> GetToken(string userName, string passWord)
var request = new HttpRequestMessage(HttpMethod.Post, "api/auth/login");
request.Headers.Authorization = new AuthenticationHeaderValue(
"Basic", Convert.ToBase64String(Encoding.UTF8.GetBytes($" userName: passWord")));
request.Headers.Host = "api.my-host.com";
request.Headers.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
var response = await _httpClient.SendAsync(request);
response.EnsureSuccessStatusCode();
using var responseStream = await response.Content.ReadAsStreamAsync();
var authResult = await JsonSerializer.DeserializeAsync<AuthResult>(responseStream);
return authResult == null ? "" : authResult.Access_Token;
根据要求,这里是 Postman 结果的屏幕截图:
我创建了一个 HttpGet 请求,并在代码中添加了来自 Postman 的不记名令牌,然后我收到了数据。只是令牌请求好像有问题。
还有我的控制器:
namespace AmsAPI.Controller
[Produces("application/json")]
[Route("api/auth")]
[ApiController]
[Authorize]
public class AuthenticationController : ControllerBase
private readonly IAuthenticationManager _authenticationManager;
public AuthenticationController(IAuthenticationManager authenticationManager)
_authenticationManager = authenticationManager;
[HttpPost("login"), AllowAnonymous]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesDefaultResponseType]
public async Task<ActionResult> Login([FromHeader] byte[] basic)
if (!ModelState.IsValid) return BadRequest();
string Basic = Encoding.UTF8.GetString(basic);
var splitBasic = Basic.Split(':');
AuthCredentials credentials = new()
UserName = splitBasic[0],
Password = splitBasic[1]
;
return await _authenticationManager.SignInCheck(credentials) ?
Ok(new
message = string.Format("User 0 successfully logged in.", credentials.UserName),
access_token = await _authenticationManager.CreateToken(),
token_type = "bearer",
expires_in = "3600"
) :
Unauthorized();
[HttpGet("user")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesDefaultResponseType]
public async Task<List<User>> GetUser() => await _authenticationManager.GetUser();
【问题讨论】:
请尝试通过邮递员请求令牌,并将结果显示给我们。我们需要检查这个http请求的内容吗? 共享您的完整控制器?您的控制器是否允许annonymous
请求?令牌控制器应该允许匿名请求。
那么 Postman 也无法工作...控制器有 annonymous
请求
您能否添加完整的控制器类,但仍不清楚问题所在
这是完整的控制器。不知道你在找什么? Postman从控制器收到正确的数据,但是客户端总是收到Bad Request错误,不知道为什么?
【参考方案1】:
嗯,我已经成功重现了你的问题。
您收到
400
是因为它正在搜索SSL
凭据,但是 默认情况下,我们的请求没有证书绑定,它没有 必需的。所以要处理这个400
异常,你必须使用HttpClientHandler
将绕过证书错误。这样你就可以 尝试以下方式以成功获取令牌响应。
HTTP Request:
public async Task<string> GetToken()
var user = new UserCred();
user.user_name = "admin";
user.password = "123456";
var handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => return true; ;
var client = new HttpClient(handler);
var json = JsonConvert.SerializeObject(user);
var data = new StringContent(json, Encoding.UTF8, "application/json");
var url = "http://localhost:21331/api/Authentication/login";
var response = await client.PostAsync(url, data);
string result = response.Content.ReadAsStringAsync().Result;
Console.WriteLine(result);
return result;
Output:
Note:
您需要添加以下代码 sn-p 来解决您的问题。但我喜欢以上述方式调用HTTP POST
请求以减少它 干净的。您可以继续使用您的代码,只需调整我的建议即可。
var handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => return true; ;
var client = new HttpClient(handler);
希望以上步骤能相应解决您的问题。
【讨论】:
【参考方案2】:Postman 似乎将基本授权标头作为 Http 请求的内容而不是在标头中发送,但我的 Web 应用程序在标头中正确实现了授权。 所以在 WebApi 中它看起来像
[Authorize]
[Route("api/auth")]
[ApiController]
public class AuthenticationController : ControllerBase
private readonly IAuthenticationManager _authenticationManager;
public AuthenticationController(IAuthenticationManager authenticationManager)
_authenticationManager = authenticationManager;
[HttpPost("login"), AllowAnonymous]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesDefaultResponseType]
public async Task<ActionResult> Login()
//check if header has Authorization
if (!Request.Headers.ContainsKey("Authorization")) return BadRequest();
try
AuthenticationHeaderValue authenticationHeaderValue = AuthenticationHeaderValue.Parse(Request.Headers["Authorization"]);
if (authenticationHeaderValue == null) throw new Exception();
var bytes = Convert.FromBase64String(authenticationHeaderValue.Parameter ?? throw new Exception());
string[] creds = Encoding.UTF8.GetString(bytes).Split(':');
AuthCredentials credentials = new()
UserName = creds[0],
Password = creds[1]
;
return await _authenticationManager.SignInCheck(credentials) ?
Ok(new
message = string.Format("User 0 successfully logged in.", credentials.UserName),
access_token = await _authenticationManager.CreateToken(),
token_type = "bearer",
expires_in = "3600"
) :
Unauthorized();
catch (Exception)
return BadRequest();
我的要求如下:
public async Task<string> GetToken(string userName, string passWord)
//set request
var request = new HttpRequestMessage(HttpMethod.Post, "api/auth/login");
//set Header
request.Headers.Authorization = new AuthenticationHeaderValue(
"Basic", Convert.ToBase64String(Encoding.UTF8.GetBytes($" userName: passWord")));
//get response
var response = await _httpClient.SendAsync(request);
response.EnsureSuccessStatusCode();
using var responseStream = await response.Content.ReadAsStreamAsync();
var authResult = await JsonSerializer.DeserializeAsync<AuthResult>(responseStream);
var token = authResult.Access_Token;
return authResult == null ? "Authorization failed!" : "Bearer token successfully created!";
并且httpClient被外包到一个Service中
public static void ConfigureServices(this IServiceCollection services)
var url = Environment.GetEnvironmentVariable("amsApiUrl");
var host = Environment.GetEnvironmentVariable("amsHostUrl");
//set HttpClient
services.AddHttpClient<IAmsAccountService, AmsAccountService>(c =>
c.BaseAddress = new Uri(url ?? "");
c.DefaultRequestHeaders.Accept.Clear();
c.DefaultRequestHeaders.Host = host;
c.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
c.Timeout = TimeSpan.FromSeconds(10);
)
.ConfigurePrimaryHttpMessageHandler(() =>
return new HttpClientHandler()
CookieContainer = new CookieContainer(),
ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) =>
return true;
;
);
【讨论】:
以上是关于对 Web api 的 ASP.NET Core 应用程序 http 客户端请求的主要内容,如果未能解决你的问题,请参考以下文章
ASP.NET Core Web API InvalidOperationException:无法解析服务 [重复]
ASP.NET Core Web API + Angular 对预检请求的响应未通过访问控制检查:预检请求不允许重定向
ASP.NET Core 实战:使用 ASP.NET Core Web API 和 Vue.js 搭建前后端分离项目