c#-ASP.NET身份电话号码令牌寿命和SMS限制
作者:互联网
我正在使用ASP.NET Identity 2.0构建2因素注册API.
我想让用户能够按需确认他们的电话号码,因此即使他们在注册时未确认自己的电话号码,他们也总是可以请求将通过短信发送的新令牌(向我的API发出请求)并在页面上输入它(也向我的API发出请求).
在负责发送令牌的方法中,我将生成令牌并将其发送,如下所示:
var token = await UserManager.GeneratePhoneConfirmationTokenAsync(user.Id);
var message = new SmsMessage
{
Id = token,
Recipient = user.PhoneNumber,
Body = string.Format("Your token: {0}", token)
};
await UserManager.SmsService.SendAsync(message);
在UserManager中:
public virtual async Task<string> GeneratePhoneConfirmationTokenAsync(TKey userId)
{
var number = await GetPhoneNumberAsync(userId);
return await GenerateChangePhoneNumberTokenAsync(userId, number);
}
每次我调用方法时,都会收到包含令牌的SMS消息,问题是用户可以无限次调用该方法,并且很容易产生费用-每个SMS =费用.
我想将用户可以对该方法执行的请求数量限制为每X分钟一次.
我还注意到,当我执行多个请求时,我得到了相同的令牌,我已经测试了我的方法,它看起来该令牌在3分钟内有效,因此,如果我在那一分钟的时间范围内进行请求,我将获得相同的令牌.
理想情况下,我希望有一个参数,该参数使我可以指定请求和电话确认令牌寿命之间的时间间隔.
我尝试使用以下方法在UserManager类中设置令牌寿命:
appUserManager.UserTokenProvider = new DataProtectorTokenProvider<User,int>(dataProtectionProvider.Create("ASP.NET Identity"))
{
TokenLifespan = new TimeSpan(0,2,0)//2 minutes
};
但这只会影响电子邮件确认链接中的令牌.
我是否需要在用户表中添加额外的字段来保存令牌有效期并在每次我想要生成和发送新令牌时对其进行检查?是否有更简单的方法?
如何指定ASP.NET Identity将生成相同电话号码确认令牌的时间间隔?
解决方法:
我不是专家,但是我有同样的问题,并在Google的帮助下找到了这两个线程.
https://github.com/aspnet/Identity/issues/465
我将假设您是正确的,基于AspNet Identity github的讨论,默认时间限制为3分钟.
希望链接的讨论包含您配置新的时间限制所需的答案.
关于速率限制,我正在使用以下基于松散讨论How do I implement rate limiting in an ASP.NET MVC site?的代码
class RateLimitCacheEntry
{
public int RequestsLeft;
public DateTime ExpirationDate;
}
/// <summary>
/// Partially based on
/// https://stackoverflow.com/questions/3082084/how-do-i-implement-rate-limiting-in-an-asp-net-mvc-site
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class RateLimitAttribute : ActionFilterAttribute
{
private static Logger Log = LogManager.GetCurrentClassLogger();
/// <summary>
/// Window to monitor <see cref="RequestCount"/>
/// </summary>
public int Seconds { get; set; }
/// <summary>
/// Maximum amount of requests to allow within the given window of <see cref="Seconds"/>
/// </summary>
public int RequestCount { get; set; }
/// <summary>
/// ctor
/// </summary>
public RateLimitAttribute(int s, int r)
{
Seconds = s;
RequestCount = r;
}
public override void OnActionExecuting(HttpActionContext actionContext)
{
try
{
var clientIP = RequestHelper.GetClientIp(actionContext.Request);
// Using the IP Address here as part of the key but you could modify
// and use the username if you are going to limit only authenticated users
// filterContext.HttpContext.User.Identity.Name
var key = string.Format("{0}-{1}-{2}",
actionContext.ActionDescriptor.ControllerDescriptor.ControllerName,
actionContext.ActionDescriptor.ActionName,
clientIP
);
var allowExecute = false;
var cacheEntry = (RateLimitCacheEntry)HttpRuntime.Cache[key];
if (cacheEntry == null)
{
var expirationDate = DateTime.Now.AddSeconds(Seconds);
HttpRuntime.Cache.Add(key,
new RateLimitCacheEntry
{
ExpirationDate = expirationDate,
RequestsLeft = RequestCount,
},
null,
expirationDate,
Cache.NoSlidingExpiration,
CacheItemPriority.Low,
null);
allowExecute = true;
}
else
{
// Allow and decrement
if (cacheEntry.RequestsLeft > 0)
{
HttpRuntime.Cache.Insert(key,
new RateLimitCacheEntry
{
ExpirationDate = cacheEntry.ExpirationDate,
RequestsLeft = cacheEntry.RequestsLeft - 1,
},
null,
cacheEntry.ExpirationDate,
Cache.NoSlidingExpiration,
CacheItemPriority.Low,
null);
allowExecute = true;
}
}
if (!allowExecute)
{
Log.Error("RateLimited request from " + clientIP + " to " + actionContext.Request.RequestUri);
actionContext.Response
= actionContext.Request.CreateResponse(
(HttpStatusCode)429,
string.Format("You can call this {0} time[s] every {1} seconds", RequestCount, Seconds)
);
}
}
catch(Exception ex)
{
Log.Error(ex, "Error in filter attribute");
throw;
}
}
}
public static class RequestHelper
{
/// <summary>
/// Retrieves the client ip address from request
/// </summary>
public static string GetClientIp(HttpRequestMessage request)
{
if (request.Properties.ContainsKey("MS_HttpContext"))
{
return ((HttpContextWrapper)request.Properties["MS_HttpContext"]).Request.UserHostAddress;
}
if (request.Properties.ContainsKey(RemoteEndpointMessageProperty.Name))
{
RemoteEndpointMessageProperty prop;
prop = (RemoteEndpointMessageProperty)request.Properties[RemoteEndpointMessageProperty.Name];
return prop.Address;
}
return null;
}
}
我也看过几次推荐这个库:
https://github.com/stefanprodan/WebApiThrottle
标签:asp-net-web-api2,asp-net-identity-2,asp-net,c 来源: https://codeday.me/bug/20191118/2025585.html