语音呼叫的Twilio请求验证始终失败(但适用于SMS)

问题描述 投票:0回答:2

我根据AuthorizationHandler实现了an official Twilio tutorial,但它仅适用于与SMS相关的请求,但不适用于与语音相关的请求(始终无法通过验证)。

以下是应用于不同控制器的唯一一个AuthorizationHandler,它接受来自Twilio的POST请求,以通知我的API入站和出站语音呼叫,入站SMS以及状态更改为出站SMS:

public class TwilioInboundRequestAuthorizationHandler : AuthorizationHandler<TwilioInboundRequestRequirement>
{
    private readonly RequestValidator _requestValidator;

    public TwilioInboundRequestAuthorizationHandler(IOptionsSnapshot<AppOptions> options)
    {
        // Initialize the validator
        _requestValidator = new RequestValidator(options.Value.TwilioAuthToken);
    }

    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, TwilioInboundRequestRequirement requirement)
    {
        if (context.Resource is AuthorizationFilterContext mvcContext)
        {
            // Examine MVC-specific things like routing data.
            HttpRequest httpRequest = mvcContext.HttpContext.Request;

            if (IsValidRequest(httpRequest))
            {
                context.Succeed(requirement);
            }
            else
            {
                /* Omitted some code that logs the error to a cloud service */
                context.Fail();
            }
        }
        else
        {
            throw new NotImplementedException();
        }

        // Check if the requirement is fulfilled.
        return Task.CompletedTask;
    }

    private bool IsValidRequest(HttpRequest request) {
        // The Twilio request URL
        var requestUrl = RequestRawUrl(request);
        var parameters = ToDictionary(request.Form);
        // The X-Twilio-Signature header attached to the request
        var signature = request.Headers["X-Twilio-Signature"];
        return _requestValidator.Validate(requestUrl, parameters, signature);
    }

    private static string RequestRawUrl(HttpRequest request)
    {
        return $"{request.Scheme}://{request.Host}{request.Path}{request.QueryString}";
    }

    private static IDictionary<string, string> ToDictionary(IFormCollection collection)
    {
        return collection.Keys
            .Select(key => new { Key = key, Value = collection[key] })
            .ToDictionary(p => p.Key, p => p.Value.ToString());
    }
}

public class TwilioInboundRequestRequirement : IAuthorizationRequirement
{
}

编辑:

根据Twilio Support的建议,我应该更改RequestRawUrl以从URL中删除端口号。但是,这导致验证仅适用于语音呼叫,而对于SMS,它不再起作用(与原始问题相反)。我怀疑Twilio在语音或短信的请求标题中设置了错误的签名。

我改变了RequestRawUrl函数

private static string RequestRawUrl(HttpRequest request)
{
    return $"{request.Scheme}://{request.Host}{request.Path}{request.QueryString}";
}

private static string RequestRawUrl(HttpRequest request)
{
    return $"{request.Scheme}://{request.Host.Host}{request.Path}{request.QueryString}";
}
c# twilio asp.net-core-2.0 asp.net-core-webapi twilio-api
2个回答
0
投票

我们遇到了类似的问题。它归结为对于某些方法,(如SMS)请求URL以https形式出现,而其他方法(如TwiML语音脚本回调)请求以http编写。

如果请求以http编写,则.Validate(...)方法将失败,即使它是有效请求。

因此,为了使Twilio请求验证器工作,我们只需重写请求URL。

    private bool IsValidRequest(HttpRequestBase request)
    {
        var signature = request.Headers["X-Twilio-Signature"];
        Debug.WriteLine(request.Headers["X-Twilio-Signature"]);
        var requestUrl = rewriteUri(request.Url.AbsoluteUri);
        Debug.WriteLine("URI is: " + rewriteUri(request.Url.AbsoluteUri));

        return _requestValidator.Validate(requestUrl, request.Form, signature);
    }

    private string rewriteUri(string absoluteUri)
    {
        //check to make sure we're not replacing 'https' with 'httpss'
        if (!absoluteUri.Contains("https"))
        {
            return Regex.Replace(absoluteUri, @"http", "https");
        }
        return absoluteUri;
    }

-1
投票

如果您使用ngrok,验证程序需要ngrok URL(我认为与其他代理相同)在PHP中,原始主机可以从HTTP_X_ORIGINAL_HOST获取,也许这会对您有所帮助

© www.soinside.com 2019 - 2024. All rights reserved.