我有一系列Web API控制器,它们返回AngularJS前端消耗的数据。
我担心编写一个机器人脚本非常简单,只需要调用它就可以从数据库中提取所有数据。虽然这些信息是免费提供的,但我需要花费数小时/周/月/年来整理所有信息 - 这实际上是我网站的整个USP。如果有人通过从服务中提取数据来窃取我的数据,我会感到沮丧。
简单地添加public class ProductsController : ApiController
{
public IHttpActionResult Get(WebApiToken token, int id)
{
if (token == null)
return BadRequest("Token not supplied");
ITokenValidator requestValidator;
// Some kind of a factory to decide how to validate the token that's been provided.
requestValidator = new GuidTokenValidator();
if (requestValidator.ValidateToken(token))
{
return Ok(string.Format("Some JSON would be returned here representing product ID {0}", id));
}
else
return BadRequest("Token validation failed");
}
}
无济于事,因为它可以免费注册。
我已经决定,我会向API提交一些令牌,这些令牌将被验证。主要是这将是一个解决的Captcha,但它可能在未来变化,所以我使它可扩展。因此,我在一个“?token = TypeID,TokenValue”参数中发送一个令牌类型和令牌值,并带有一个类型转换器来拾取它并将其转换为令牌对象。
所以我的问题是 - 将令牌和请求一起发送到Web API控制器有什么好的做法?我这样做了,这是对的吗?我已经读过发送查询字符串来进行身份验证并不是非常RESTful - 但它确实很有效。
样本概念验证
我的控制器:
<script type="text/javascript">
$(document).ready(function () {
$("#postTest").click(function () {
$.ajax({
type: "GET",
dataType: "json",
url: "/api/Products/2?token=2,OK",
success: function (data) {
alert(data);
},
error: function (error) {
// Error handler
}
});
});
});
</script>
Javascript调用它:
[TypeConverter(typeof(TokenConverter))]
public class WebApiToken : IToken
{
public TokenType TokenType { get; set; }
public string Token { get; set; }
public static bool TryParse(string s, out WebApiToken result)
{
result = null;
var parts = s.Split(',');
if (parts.Length != 2)
{
return false;
}
int tokenTypeId;
if (int.TryParse(parts[0], out tokenTypeId))
{
result = new WebApiToken() { TokenType = (TokenType)tokenTypeId, Token = parts[1] };
return true;
}
return false;
}
}
令牌定义:
public class TokenConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, System.Type sourceType)
{
if (sourceType == typeof(string))
{
return true;
}
return base.CanConvertFrom(context, sourceType);
}
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{
if (value is string)
{
WebApiToken token;
if (WebApiToken.TryParse((string)value, out token))
{
return token;
}
}
return base.ConvertFrom(context, culture, value);
}
}
类型转换器:
GET http://localhost:58106/api/Products/2?token=2,OK HTTP/1.1 Host: localhost:58106 Connection: keep-alive Accept: application/json, text/javascript, */*; q=0.01 X-Requested-With: XMLHttpRequest User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.152 Safari/537.36 Referer: http://localhost:58106/ Accept-Encoding: gzip, deflate, sdch Accept-Language: en-GB,en-US;q=0.8,en;q=0.6
提琴手请求:
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?YzpcdXNlcnNcYmVuLnNsb2FuXGRvY3VtZW50c1x2aXN1YWwgc3R1ZGlvIDIwMTNcUHJvamVjdHNcV2ViQVBJQWN0aW9uRmlsdGVyc1xXZWJBUElBY3Rpb25GaWx0ZXJzXGFwaVxQcm9kdWN0c1wy?=
X-Powered-By: ASP.NET
Date: Wed, 20 May 2015 11:59:55 GMT
Content-Length: 60
"Some JSON would be returned here representing product ID 2"
提琴手回应:
{{1}}