首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >对于语音呼叫,Twilio请求验证总是失败(但对SMS有效)

对于语音呼叫,Twilio请求验证总是失败(但对SMS有效)
EN

Stack Overflow用户
提问于 2018-04-17 01:20:00
回答 3查看 1.5K关注 0票数 1

我已经根据AuthorizationHandler实现了一个官方的“Twilio教程”,但是它只适用于与短信相关的请求,而不适用于与语音相关的请求(验证总是失败)。

下面是唯一应用于不同控制器的AuthorizationHandler,这些控制器接受Twilio的POST请求,将入站和出站语音呼叫、入站短消息和状态更改通知我的API:

代码语言:javascript
复制
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支持的建议,我应该更改RequestRawUrl以删除URL中的端口号。然而,这会导致验证只适用于语音通话,而对于SMS则不再起作用(与最初的问题相反)。我怀疑Twilio在语音或短信的请求头中设置了错误的签名。

我将RequestRawUrl函数改为

代码语言:javascript
复制
private static string RequestRawUrl(HttpRequest request)
{
    return $"{request.Scheme}://{request.Host}{request.Path}{request.QueryString}";
}

代码语言:javascript
复制
private static string RequestRawUrl(HttpRequest request)
{
    return $"{request.Scheme}://{request.Host.Host}{request.Path}{request.QueryString}";
}
EN

回答 3

Stack Overflow用户

发布于 2019-01-07 21:11:32

我们也有过类似的问题。归根结底,对于某些方法(如SMS),请求URL以https的形式出现,而其他方法(如TwiML语音脚本回调)则以http的形式出现。

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

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

代码语言:javascript
复制
    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;
    }
票数 2
EN

Stack Overflow用户

发布于 2021-10-20 18:19:34

在本地运行ngrok时,我遇到了完全相同的问题,但在部署时却不是这样。我发现RequestValidator需要原始ngrok,但默认情况下我们要传递localhost。最后我解决了这个问题:

代码语言:javascript
复制
    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);
    }
票数 0
EN

Stack Overflow用户

发布于 2019-03-21 22:57:10

如果您使用ngrok,验证器希望ngrok (我认为与其他代理相同)在HTTP_X_ORIGINAL_HOST中可以获得原始主机,也许这会对您有所帮助。

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49868419

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档