首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >生成安全URL安全令牌

生成安全URL安全令牌
EN

Code Review用户
提问于 2019-01-28 10:06:50
回答 2查看 4.6K关注 0票数 5
代码语言:javascript
复制
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表中。

我在这个站点和其他站点上看到了其他的实现,但它们似乎都是不必要的复杂。我是不是遗漏了什么?

EN

回答 2

Code Review用户

回答已采纳

发布于 2019-01-28 17:39:42

次要建议:

代码语言:javascript
复制
public class UrlToken

该类没有实例数据,因此可以将其设置为static

代码语言:javascript
复制
public static class UrlToken

微软的命名指南和他们的框架设计指南建议不要使用下划线,也不要对常量使用PascalCasing,所以

代码语言:javascript
复制
    private const int BYTE_LENGTH = 32; 

可以是:

代码语言:javascript
复制
    private const int ByteLength = 32; 

然而,即使是这个名字也不能告诉我们它的用途。我们再试一次:

代码语言:javascript
复制
    private const int NumberOfRandomBytes = 32; 

在XML注释中输入错误/拼写错误:“编码”被写成"endcoding“。

有混合的大括号格式。微软的指导方针(见上面的链接)建议,开封大括号应该在自己的线上。

代码语言:javascript
复制
        using (RNGCryptoServiceProvider provider = new RNGCryptoServiceProvider()) { 

至:

代码语言:javascript
复制
        using (RNGCryptoServiceProvider provider = new RNGCryptoServiceProvider())
        { 

顺便说一句,对您正确使用using结构表示赞赏!看上去棒极了!

票数 5
EN

Code Review用户

发布于 2019-01-29 07:41:38

除了mr先生之外,在审查中没有什么可做的。切割机已经写好了。

但是,为了使其更加灵活,您可以提供字节数作为参数,而不是常量成员值:

代码语言:javascript
复制
      public static string GenerateToken(int numberOfBytes = 32)

对类进行重构以处理这一点,可以是:

代码语言:javascript
复制
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;
    }
  }
}

类是可以的,如果您不时地在不同的场合使用它,但是如果您想同时生成更多的代码,您可以考虑像静态方法那样实现一个工厂:

代码语言:javascript
复制
  public static IEnumerable<string> GenerateTokens(int numberOfBytes = 32)

这样做的好处是,您可以避免(可能昂贵)为每个令牌实例化一个新的数字生成器。

为适应这一需要,可对该类进行修订,具体如下:

代码语言:javascript
复制
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();
      }
    }
  }
}

用法:

代码语言:javascript
复制
  foreach (string token in NewUrlToken.GenerateTokens().Take(10))
  {
    Console.WriteLine(token);
  }
票数 3
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/212370

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档