using Microsoft.AspNetCore.WebUtilities;
using System.Security.Cryptography;
namespace UserManager.Cryptography
{
public class UrlToken
{
private const int BYTE_LENGTH = 32;
/// <summary>
/// Generate a fixed length token that can be used in url without endcoding it
/// </summary>
/// <returns></returns>
public static string GenerateToken()
{
// get secure array bytes
byte[] secureArray = GenerateRandomBytes();
// convert in an url safe string
string urlToken = WebEncoders.Base64UrlEncode(secureArray);
return urlToken;
}
/// <summary>
/// Generate a cryptographically secure array of bytes with a fixed length
/// </summary>
/// <returns></returns>
private static byte[] GenerateRandomBytes()
{
using (RNGCryptoServiceProvider provider = new RNGCryptoServiceProvider()) {
byte[] byteArray = new byte[BYTE_LENGTH];
provider.GetBytes(byteArray);
return byteArray;
}
}
}
}我创建了上面的类(C#,.Net Core2.0)来生成一个加密安全的字符串令牌,它是URL安全的,因此它可以在URL中使用,而无需进行编码。
我将在用户管理器应用程序中使用该令牌作为GET参数(例如www.site.com/verify/?token=v3XYPmQ3wD_RtOjH1lMekXloBGcWqlLfomgzIS1mCGA),其中我将使用令牌来验证用户电子邮件或恢复用户密码。
以上链接将以电子邮件的形式发送给已请求该服务的用户。
我将令牌存储到带有相关到期日期时间的DB表中。
我在这个站点和其他站点上看到了其他的实现,但它们似乎都是不必要的复杂。我是不是遗漏了什么?
发布于 2019-01-28 17:39:42
次要建议:
public class UrlToken该类没有实例数据,因此可以将其设置为static:
public static class UrlToken微软的命名指南和他们的框架设计指南建议不要使用下划线,也不要对常量使用PascalCasing,所以
private const int BYTE_LENGTH = 32; 可以是:
private const int ByteLength = 32; 然而,即使是这个名字也不能告诉我们它的用途。我们再试一次:
private const int NumberOfRandomBytes = 32; 在XML注释中输入错误/拼写错误:“编码”被写成"endcoding“。
有混合的大括号格式。微软的指导方针(见上面的链接)建议,开封大括号应该在自己的线上。
using (RNGCryptoServiceProvider provider = new RNGCryptoServiceProvider()) { 至:
using (RNGCryptoServiceProvider provider = new RNGCryptoServiceProvider())
{ 顺便说一句,对您正确使用using结构表示赞赏!看上去棒极了!
发布于 2019-01-29 07:41:38
除了mr先生之外,在审查中没有什么可做的。切割机已经写好了。
但是,为了使其更加灵活,您可以提供字节数作为参数,而不是常量成员值:
public static string GenerateToken(int numberOfBytes = 32)对类进行重构以处理这一点,可以是:
public class ReviewdUrlToken
{
/// <summary>
/// Generate a fixed length token that can be used in url without endcoding it
/// </summary>
/// <returns></returns>
public static string GenerateToken(int numberOfBytes = 32)
{
return WebEncoders.Base64UrlEncode(GenerateRandomBytes(numberOfBytes));
}
/// <summary>
/// Generate a cryptographically secure array of bytes with a fixed length
/// </summary>
/// <returns></returns>
private static byte[] GenerateRandomBytes(int numberOfBytes)
{
using (RNGCryptoServiceProvider provider = new RNGCryptoServiceProvider())
{
byte[] byteArray = new byte[numberOfBytes];
provider.GetBytes(byteArray);
return byteArray;
}
}
}类是可以的,如果您不时地在不同的场合使用它,但是如果您想同时生成更多的代码,您可以考虑像静态方法那样实现一个工厂:
public static IEnumerable<string> GenerateTokens(int numberOfBytes = 32)这样做的好处是,您可以避免(可能昂贵)为每个令牌实例化一个新的数字生成器。
为适应这一需要,可对该类进行修订,具体如下:
public class NewUrlToken : IDisposable
{
RNGCryptoServiceProvider _provider = new RNGCryptoServiceProvider();
int _numberOfBytes;
public NewUrlToken(int numberOfBytes)
{
_numberOfBytes = numberOfBytes;
}
/// <summary>
/// Generate a cryptographically secure array of bytes with a fixed length
/// </summary>
/// <returns></returns>
private byte[] GenerateRandomBytes()
{
byte[] byteArray = new byte[_numberOfBytes];
_provider.GetBytes(byteArray);
return byteArray;
}
public void Dispose()
{
// TODO Implement the proper Disposable pattern.
if (_provider != null)
{
_provider.Dispose();
_provider = null;
}
}
private string GenerateToken()
{
return WebEncoders.Base64UrlEncode(GenerateRandomBytes());
}
/// <summary>
/// Generate a fixed length token that can be used in url without endcoding it
/// </summary>
/// <returns></returns>
public static string GenerateToken(int numberOfBytes = 32)
{
return GenerateTokens(numberOfBytes).First();
}
public static IEnumerable<string> GenerateTokens(int numberOfBytes = 32)
{
using (NewUrlToken factory = new NewUrlToken(numberOfBytes))
{
while (true)
{
yield return factory.GenerateToken();
}
}
}
}用法:
foreach (string token in NewUrlToken.GenerateTokens().Take(10))
{
Console.WriteLine(token);
}https://codereview.stackexchange.com/questions/212370
复制相似问题