简体   繁体   English

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

[英]Twilio Request Validation always fail for Voice Call (but works for SMS)

I have implemented a AuthorizationHandler according to an official Twilio tutorial but it only works for SMS-related requests but not voice-related requests (always fail the validation).我已经根据官方 Twilio 教程实现了AuthorizationHandler ,但它仅适用于与 SMS 相关的请求,而不适用于与语音相关的请求(始终无法通过验证)。

Below is the one and only AuthorizationHandler applied to different controllers that accept POST request from Twilio to notify my API of inbound and outbound voice calls, inbound SMS, and status change to outbound 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
{
}

EDIT:编辑:

According to a suggestion from Twilio Support, I should change the RequestRawUrl to strip away the port number from the URL.根据 Twilio 支持的建议,我应该更改RequestRawUrl以从 URL 中去除端口号。 However, that causes the validation working for voice calls only, while for SMS it doesn't work anymore (opposite to the original issue).但是,这会导致验证仅适用于语音通话,而对于 SMS,它不再起作用(与原始问题相反)。 I suspect Twilio has been setting an incorrect signature in the request header for either voice or SMS.我怀疑 Twilio 在语音或 SMS 的请求标头中设置了错误的签名。

I changed the RequestRawUrl function from我将RequestRawUrl函数从

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

to

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

We had a similar problem. 我们有一个类似的问题。 What it boiled down to was that for some methods, (like SMS) the request URL comes in as https, and other methods (like TwiML voice script callbacks) the request comes in written as http. 归结为,对于某些方法(例如SMS),请求URL以https形式出现,而在其他方法(例如TwiML语音脚本回调)中,请求以http形式出现。

If the request comes in written as http, the .Validate(...) method will fail on you, even though it is a valid request. 如果该请求以http形式发出,则.Validate(...)方法将对您失败,即使它是有效请求。

So to get the Twilio request validator to work, we simply rewrite the request URL. 因此,要使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;
    }

I was having the exact same issue when running locally behind ngrok, but not when deployed.在 ngrok 后面本地运行时,我遇到了完全相同的问题,但在部署时却没有。 I figured out that the RequestValidator expects the original ngrok URL, but by default we are passing localhost.我发现 RequestValidator 需要原始的 ngrok URL,但默认情况下我们传递的是 localhost。 I ended up solving it like so:我最终像这样解决它:

    private bool IsValidRequest(HttpRequest request)
    {
        var requestUrl = RequestRawUrl(request);
        var parameters = ToDictionary(request.Form);
        var signature = request.Headers["X-Twilio-Signature"];

        // Check if we are running locally and need to pass ngrok through for validation to succeed.
        if (request.Headers.ContainsKey("X-Original-Host") && request.Headers["X-Original-Host"][0].Contains("ngrok"))
        {
            requestUrl = requestUrl.Replace(request.Headers["Host"][0], request.Headers["X-Original-Host"][0]);
        }

        return _requestValidator.Validate(requestUrl, parameters, signature);
    }

如果您使用ngrok,则验证程序会期望ngrok URL(我认为与其他代理相同)在PHP中,原始主机可以从HTTP_X_ORIGINAL_HOST获取,也许这可以以某种方式帮助您

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM