我已根据an official Twilio tutorial实施了AuthorizationHandler
,但它仅适用于与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支持部门的建议,我应该更改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}";
}
答案 0 :(得分: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 :(得分:-1)
如果您使用ngrok,则验证程序将使用ngrok URL(我认为与其他代理相同) 在PHP中,原始主机可以从HTTP_X_ORIGINAL_HOST获取,也许这可以以某种方式帮助您