我有一个从Javascript代码到C#Web Api的Ajax请求,我在尝试在实际处理请求之前验证reCaptcha信息。当我在VS2015社区本地测试它时(localhost:port /下的IIS Express)就像魅力一样,但当我将它部署在我的测试服务器(在机器/文件夹下的单独机器上的IIS)或甚至在我的本地测试IIS中时(在localhost但在locahost / folder /下,请求失败,代码为500,所以我得到了自己的“服务器错误”消息
这是我的API方法
[HttpPost]
public List<Thing> GetThings(string parameter1, string parameter2)
{
List<Thing> ListThings = new List<Thing>();
try
{
var serializer = new JsonSerializer();
bool recaptchaValidation = false;
using (var sr = new StreamReader(Request.Content.ReadAsStreamAsync().Result))
{
using (var jsonTextReader = new JsonTextReader(sr))
{
dynamic captchaResponse = serializer.Deserialize(jsonTextReader, typeof(ReCaptchaEncodedResponse));
recaptchaValidation = ReCaptcha.ReCaptcha.Validate(captchaResponse.captchaResponse, System.Configuration.ConfigurationManager.AppSettings["recaptchaPrivateKey"]) == "True" ? true : false;
}
}
if (!recaptchaValidation)
return null;
... Code for getting the list of things...
return ListThings;
}
... Code for processing exceptions ...
}
这是我要求它的JS
$scope.submitForm = function () {
var captchaResponse = grecaptcha.getResponse();
if (!captchaResponse) {
refreshCatcha();
alert("Wrong captcha");
return;
}
$("input").prop('disabled', 'disabled');
$http.post('api/ManageThingsApi/GetThings/' + $scope.Thing.Param1 + "/" + $scope.Thing.Param2,
{ "captchaResponse": captchaResponse }).success(function (data) {
if (data === null) {
refreshCatcha();
alert("Not found");
}
else if (data.length === 0) {
refreshCatcha();
alert("Not found");
}
else {
$scope.Data = data;
$location.path('/ShowThings');
$("#Search").css({ 'display': "none" });
}
$("input").prop('disabled', '');
}).error(function (error) {
$("input").prop('disabled', '');
alert("Server error");
});
}
这是我的ReCaptchaEncodedResponse类
public class ReCaptchaEncodedResponse
{
public string captchaResponse { get; set; }
}
我不确定,但我开始相信问题出现在POST参数(我读过的正文)和服务器中的Request.Content之间。
那么什么错?
已更新:更改了API方法,使其仅接收来自帖子的所有信息,并删除了难看的阅读请求正文。
修改后的API方法:
public List<Thing> GetThings([FromBody]SearchRequest srequest)
{
List<Thing> ListThings = new List<Thing>();
bool recaptchaValidation = false;
recaptchaValidation = ReCaptcha.ReCaptcha.Validate(srequest.ValidationToken, System.Configuration.ConfigurationManager.AppSettings["recaptchaPrivateKey"]) == "True" ? true : false;
if (!recaptchaValidation)
return null;
...
}
修改了JS:
$scope.submitForm = function () {
$scope.captchaResponse = grecaptcha.getResponse();
if (!$scope.captchaResponse) {
alert("Captcha verification required");
return;
}
$("input").prop('disabled', 'disabled');
var requestData = {
Param1: $scope.Thing.Param1,
Param2: $scope.Thing.Param2,
ValidationToken: $scope.captchaResponse
};
$http.post('api/ManageThingsApi/GetThings',
requestData, 'json').success(function (data) {
if (data === null) {
grecaptcha.reset();
alert("Not found");
}
else if (data.length === 0) {
grecaptcha.reset();
alert("Not found");
}
else {
$scope.Data = data;
$location.path('/ShowThings');
$("#Search").css({ 'display': "none" });
}
$("input").prop('disabled', '');
}).error(function (error) {
$("input").prop('disabled', '');
alert("Server error");
});
};
参数类:
public class SearchRequest {
public string Param1 { get; set; }
public string Param2 { get; set; }
public string ValidationToken { get; set; }
}
再次像VS2015 IIS Express中的魅力一样,来自本地IIS的错误500.
答案 0 :(得分:0)
<强>解决!强>
错误(像往常一样)来自最意想不到,愚蠢而且简单的地方,你几乎从未检查过。
这两个代码都运行良好,但我忘记设置服务器的代理以连接到Google以验证令牌。
请参阅第一次对Google的请求来自客户端(在javascript代码中),因此它使用的是浏览器的代理设置通常是对的。现在,对Google的第二次请求来自服务器(在C#代码中),因此它将使用服务器的配置和凭据进行连接。
使用本地IIS Express 进行测试时,由于IIS Express在已记录用户的凭据和配置上运行,因此它也使用与客户端相同的配置。但标准IIS 本身通常使用自己的用户凭据来运行,因此没有代理配置。
修改(和工作!)代码
[HttpPost]
public List<Thing> GetThings(ValidatedRequest requestParams)
{
List<Thing> ListThings = new List<Thing>();
if (requestParams == null)
throw new UnauthorizedAccessException("Unauthorized");
if (string.IsNullOrEmpty(requestParams.ValidationToken))
throw new UnauthorizedAccessException("Unauthorized");
JObject obj = null;
try
{
var wc = new WebClient();
var googleVerificationURL = string.Format("https://www.google.com/recaptcha/api/siteverify?secret={0}&response={1}&remoteip={2}", ConfigurationManager.AppSettings["gReCaptchaPrivateKey"], requestParams.ValidationToken, remoteIpAddress);
if (!string.IsNullOrEmpty(ConfigurationManager.AppSettings["ProxyAddress"].Trim()))
{
wc.Proxy = new WebProxy(ConfigurationManager.AppSettings["ProxyAddress"].Trim());
wc.Proxy.Credentials = new NetworkCredential(ConfigurationManager.AppSettings["ProxyUsername"].Trim(), ConfigurationManager.AppSettings["ProxyPassword"]);
}
var result = wc.DownloadString(googleVerificationURL);
wc.Dispose();
obj = JObject.Parse(result);
}
catch (Exception ex)
{
throw new InvalidOperationException("Failed to connect to reCaptcha", ex);
}
if(obj == null || !(bool)obj.SelectToken("success"))
throw new UnauthorizedAccessException("Unauthorized");
... Rest of the code ...
}
如您所见,我还在 web.config 的AppSettings部分内创建了代理地址,代理用户和代理传递的变量(可能存在安全问题)
对SearchRequest类进行了一些微小的修饰,现在已成为ValidatedRequest类
public class ValidatedRequest
{
public string ValidationToken { get; set; }
public string Data1 { get; set; }
public string Data2 { get; set; }
}
就是这样,Sayonara!