【问题标题】:Angular requests to ASP.NET return "Error Unknown" when under SSL/TLS certificate在 SSL/TLS 证书下,对 ASP.NET 的 Angular 请求返回“错误未知”
【发布时间】:2019-05-09 17:29:50
【问题描述】:

我已经解决了这个问题,但仍然没有找到任何答案: 我的 Angular 应用程序向 asp.net 发送了一堆 HTTP 请求。 Asp.net 处理请求(令牌检查等)并按顺序返回数据。 问题是,在 IIS 上,我添加了 Let's Encrypt 的 SSL/TLS 证书,并且该应用程序再也无法工作。

我发现的奇怪行为

  • 只有 login 方法有效。随后的所有请求,返回“未知错误 - 状态代码 0”
  • Asp.net 有一个拦截器,可以过滤每个请求以检查令牌。如果我发送 Authorization 标头,应用程序将失败。如果我不这样做,asp.net 会返回 404 错误,说明数据库中不存在令牌(应该如此)
  • 在 Postman 中,请求 100% 有效(甚至检查令牌的真实性)
  • 如果我在 asp.net 中删除了角度拦截器和中间件并删除了 SSL 证书。该应用程序有效
  • Chrome 抛出“net::ERR_SPDY_PROTOCOL_ERROR”异常。

我已经头疼了两天,没有找到答案。查了一下 StackOverflow、IIS 论坛、Angular 论坛、.Net 论坛……什么都没有

这里有一些代码:

角度拦截器

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);
    }

这里有一些邮递员和浏览器的截图

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

【问题讨论】:

    标签: c# asp.net angular ssl


    【解决方案1】:

    我在使用 Chrome 和自定义身份验证标头时遇到了类似的问题,给我一个 SPDY 错误。

    我将 Authorization 标头的名称更改为“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();
    

    您可能还需要将自定义身份验证标头名称添加到 Web 配置或 CORS 配置。

    希望它也适用于您的情况。

    【讨论】:

    • 刚刚将标题 Authorization 的名称更改为 X-Custom-Header 并且工作得很好。非常感谢:)
    猜你喜欢
    • 1970-01-01
    • 2016-09-23
    • 2018-03-16
    • 1970-01-01
    • 1970-01-01
    • 2011-03-05
    • 1970-01-01
    • 1970-01-01
    • 2013-07-08
    相关资源
    最近更新 更多