我已经解决了这个问题,但仍然没有找到任何答案: 我的 Angular 应用程序向 asp.net 发送了一堆 HTTP 请求。 Asp.net 处理请求( token 检查等)并按顺序返回数据。 问题是,在 IIS 上,我添加了来自 Let's Encrypt 的 SSL/TLS 证书,应用程序再也无法运行。
我注意到的奇怪行为
- 只有登录方法有效。之后的所有请求,返回“Unknown Error - Status Code 0”
- Asp.net 有一个拦截器,可以过滤每个检查 token 的请求。如果我发送 Authorization header ,应用程序将失败。如果我不这样做,asp.net 将返回 404 错误,指出数据库中不存在 token (应该如此)
- 在 Postman 中,请求 100% 有效(甚至检查 token 的真实性)
- 如果我在 asp.net 中删除 Angular 拦截器和中间件并删除 SSL 证书。应用程序有效
- Chrome 抛出“net::ERR_SPDY_PROTOCOL_ERROR”异常。
我已经想了两天了,没有找到答案。在 StackOverflow、IIS 论坛、Angular 论坛、.Net 论坛上查找......没有
这里是一些代码:
Angular 拦截器
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// Filtrar apenas pedidos feitos à API
if(req.url.match("\\api")) {
let newRequest = req.clone({
headers: new HttpHeaders({
'Content-Type':'application/json',
'Authorization':this.cookieService.get('at')
})
});
return next.handle(newRequest);
} else {
return next.handle(req);
}
}
Asp.NET 中间件
public Task Invoke(HttpContext context) {
// Check if request is redirected to ".../api/exemplo/xyx"
// To exclude the 'login' request
if (context.Request.Path.Value.StartsWith("/api")) {
// Check if request is NOT an OPTIONS
if(!context.Request.Method.Equals("OPTIONS")){
// Check for header
string auth = context.Request.Headers["Authorization"].ToString();
FbConnectionStringBuilder csb = new FbConnectionStringBuilder {
DataSource = _appSettings.DataSource,
Port = _appSettings.Port,
Database = _appSettings.Database,
UserID = _appSettings.UserID,
Password = _appSettings.Password,
ServerType = FbServerType.Default
};
// Open db
FbConnection db = new FbConnection(csb.ToString());
db.Open();
// Get the expiration date of token
string query = "SELECT DT_REVOG FROM ORGANIG_TOKEN WHERE TOKEN = @auth";
DateTime now = DateTime.UtcNow;
DateTime DateRevogToken;
try
{
DateRevogToken = db.QuerySingle<DateTime>(query, new { auth });
db.Close();
if (now >= DateRevogToken)
{
// Expired
string deleteQuery = "DELETE FROM ORGANIG_TOKEN WHERE TOKEN = @auth";
db.Execute(deleteQuery, new { auth });
context.Response.StatusCode = 401;
context.Response.WriteAsync("A token não é válida");
return Task.CompletedTask;
}
else
{
// Is valid
return _next(context);
}
} catch(Exception e) {
context.Response.StatusCode = 404;
context.Response.WriteAsync("Ocorreu um erro na verificação da token: " + e.Message);
return Task.CompletedTask;
}
}
else {
//It's a OPTIONS request. Ignore
return _next(context);
}
}
else {
// Login request. Ignore
return _next(context);
}
}
}
登录请求(asp.net)
[Route("auth/gerar_token")]
[AllowAnonymous]
[HttpPost]
public async Task<IActionResult> GerarToken([FromBody] Client c)
{
// Conexão á base de dados Firebird
FbConnectionStringBuilder csb = new FbConnectionStringBuilder
{
DataSource = _appSettings.DataSource,
Port = _appSettings.Port,
Database = _appSettings.Database,
UserID = _appSettings.UserID,
Password = _appSettings.Password,
ServerType = FbServerType.Default
};
Client client = new Client();
string login = c.login;
string pass = c.pass;
string hashedPass = null;
string responseMessage;
// Hash da password do client
using (MD5 md5Hash = MD5.Create()) { hashedPass = GetMd5Hash(md5Hash, pass); }
using (var db = new FbConnection(csb.ToString())) {
string token;
try {
await db.OpenAsync();
// Query de login
string sql = @"SELECT CD, NOME, RAMO_ACT, DESIGN, EMAIL, LOGIN, MORAD
FROM ORGANIG WHERE LOGIN = @login AND PASS = @hashedPass";
client = await db.QuerySingleAsync<Client>(sql, new { login, hashedPass });
try {
int cd_organig = client.cd;
token = GenerateRefreshToken();
DateTime dt_cria = DateTime.UtcNow;
DateTime dt_revog = dt_cria.AddHours(4);
DateTime dt_inicio = DateTime.UtcNow;
string sql_token = @"INSERT INTO ORGANIG_TOKEN(TOKEN, CD_ORGANIG, DT_CRIA, DT_REVOG) VALUES (@token, @cd_organig, @dt_cria, @dt_revog)";
db.Execute(sql_token, new { token, cd_organig, dt_cria, dt_revog });
string sql_sessao = @"INSERT INTO ORGANIG_SESSAO(CD_ORGANIG, DT_INICIO, TOKEN, DT_REVOG_TOKEN) VALUES (@cd_organig, @dt_inicio, @token, @dt_revog)";
db.Execute(sql_sessao, new { cd_organig, dt_inicio, token, dt_revog });
}
catch (Exception e) {
JObject serverErroResponse = new JObject {
{ "Ocorreu um erro no servidor. Detalhes: ", e.Message }
};
db.Close();
return StatusCode(500, serverErroResponse);
}
JObject response = new JObject {
{ "token", token },
{ "cd", client.cd },
{ "nome", client.nome }
};
db.Close();
return Ok(response);
}
catch (Exception e) {
if(e.Message.Equals("Sequence contains no elements")) {
responseMessage = "Credenciais inválidas. Por favor, tente novamente";
} else {
responseMessage = "Ocorreu um erro no servidor. Detalhes: " + e.Message;
}
JObject serverErrorResponse = new JObject {
{ "message", responseMessage }
};
db.Close();
return StatusCode(500, serverErrorResponse);
}
} // using (var db = new FbConnection(csb.ToString()))
}
请求无效的例子
[Route("api/build_organig/{cd}")]
[HttpGet]
public IActionResult BuildOrganig(int cd)
{
// Conexão á base de dados Firebird
FbConnectionStringBuilder csb = new FbConnectionStringBuilder {
DataSource = _appSettings.DataSource,
Port = _appSettings.Port,
Database = _appSettings.Database,
UserID = _appSettings.UserID,
Password = _appSettings.Password,
ServerType = FbServerType.Default
};
// Abrir conexão á base de dados
FbConnection db = new FbConnection(csb.ToString());
db.Open();
// Query para retornar os dados do procedure para uma lista
List<BuildOrganig> buildOrganigList = new List<BuildOrganig>();
buildOrganigList = db.Query<BuildOrganig>("SELECT CD, CD_BASE, NOME FROM BUILD_ORGANIG(@cd) ORDER BY NIVEL", new { cd }).ToList();
if (buildOrganigList.Count == 0) {
JObject emptyResponse = new JObject {
{ "count", buildOrganigList.Count },
{ "message", "Organigrama não existente" }
};
db.Close();
return StatusCode(404, emptyResponse);
}
db.Close();
return StatusCode(200, buildOrganigList);
}
下面是postman和浏览器的部分截图
如果您需要更多信息,请在评论中说明。 谢谢
最佳答案
我在使用 Chrome 和自定义身份验证 header 时遇到了类似的问题,给我一个 SPDY 错误。
我将授权 header 的名称更改为“X-Custom-Auth”,并为 OPTIONS 提供了如下特殊响应:
response.AddHeader("Access-Control-Allow-Methods", "GET, POST");
// Important: copy back the expected allowed headers
response.Headers["Access-Control-Allow-Headers"] = request.Headers["Access-Control-Request-Headers"];
response.AddHeader("Access-Control-Max-Age", "1728000");
response.Flush();
response.End();
您可能还需要将自定义身份验证 header 名称添加到 Web 配置或 CORS 配置。
希望它也适用于您的情况。
关于c# - 在 SSL/TLS 证书下,对 ASP.NET 的 Angular 请求返回 "Error Unknown",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56064669/