c# - 在 SSL/TLS 证书下,对 ASP.NET 的 Angular 请求返回 "Error Unknown"

标签 c# asp.net angular ssl

我已经解决了这个问题,但仍然没有找到任何答案: 我的 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和浏览器的部分截图

Postman login

Postman request

Postman when header is missing

Platform with errors on console

IIS config

如果您需要更多信息,请在评论中说明。 谢谢

最佳答案

我在使用 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/

相关文章:

c# - 使用隐式枚举字段来表示数值是一种不好的做法吗?

javascript - 为什么微软开发了一种名为 Typescript 的新语言,而不是创建 C# 到 Javascript 的转换器

c# - MVC4 应用程序中的 Jquery.min.map 文件 404

javascript - ionic 4中的(按键)事件未触发

angular - 类型错误 : [X] is not a function

c# - readline 然后将指针移回?

c# - 使用实体服务/存储库模式时,在模型中引用 System.Web.Security 是一种不好的做法吗?

asp.net - .Net 对象数据源错误 : Object does not match target type

javascript - 在 javascript 中设置的文本框值在服务器端页面加载事件中不可用

angular - 从 Angular2 Controller 中的模板访问局部变量