You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET中不使用Identity实现带加盐哈希的自定义登录注册

自定义.NET登录注册实现(无Identity,加盐哈希)

核心原理

注册时为每个用户生成唯一随机盐,将盐与密码结合后通过哈希算法生成不可逆的密码哈希值,最终将用户名、密码哈希、盐存储到数据库;登录时根据用户名取出对应的哈希和盐,用相同算法将输入密码与盐重新哈希,对比两次哈希值是否一致验证身份。

密码哈希工具类

封装静态类处理密码哈希生成与验证,使用.NET内置的Rfc2898DeriveBytes(基于PBKDF2安全算法):

public static class PasswordHasher
{
    // 迭代次数(建议不低于10000,值越高破解难度越大,耗时相应增加)
    private const int Iterations = 10000;
    // 哈希字节长度
    private const int HashSize = 256 / 8;
    // 盐字节长度
    private const int SaltSize = 128 / 8;

    // 生成密码哈希和盐
    public static void CreatePasswordHash(string password, out byte[] passwordHash, out byte[] passwordSalt)
    {
        if (password == null) throw new ArgumentNullException(nameof(password));
        if (string.IsNullOrWhiteSpace(password)) throw new ArgumentException("密码不能为空", nameof(password));

        using var deriveBytes = new Rfc2898DeriveBytes(password, SaltSize, Iterations, HashAlgorithmName.SHA256);
        passwordSalt = deriveBytes.Salt;
        passwordHash = deriveBytes.GetBytes(HashSize);
    }

    // 验证密码哈希是否匹配
    public static bool VerifyPasswordHash(string password, byte[] storedHash, byte[] storedSalt)
    {
        if (password == null) throw new ArgumentNullException(nameof(password));
        if (string.IsNullOrWhiteSpace(password)) throw new ArgumentException("密码不能为空", nameof(password));
        if (storedHash == null || storedHash.Length != HashSize) throw new ArgumentException("无效的哈希值", nameof(storedHash));
        if (storedSalt == null || storedSalt.Length != SaltSize) throw new ArgumentException("无效的盐值", nameof(storedSalt));

        using var deriveBytes = new Rfc2898DeriveBytes(password, storedSalt, Iterations, HashAlgorithmName.SHA256);
        var computedHash = deriveBytes.GetBytes(HashSize);

        // 逐字节对比哈希值(避免计时攻击)
        return CryptographicOperations.FixedTimeEquals(computedHash, storedHash);
    }
}

数据库实体模型

以Entity Framework Core为例,定义用户实体:

public class User
{
    public int Id { get; set; }
    public string Username { get; set; } = string.Empty;
    public byte[] PasswordHash { get; set; } = Array.Empty<byte>();
    public byte[] PasswordSalt { get; set; } = Array.Empty<byte>();
    // 可扩展字段:Email、CreateTime等
}

在DbContext中配置唯一索引:

public class AppDbContext : DbContext
{
    public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }

    public DbSet<User> Users { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<User>()
            .HasIndex(u => u.Username)
            .IsUnique(); // 确保用户名唯一
    }
}

注册功能实现

业务层实现注册逻辑:

public interface IAuthService
{
    Task<bool> RegisterAsync(string username, string password);
}

public class AuthService : IAuthService
{
    private readonly AppDbContext _dbContext;

    public AuthService(AppDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    public async Task<bool> RegisterAsync(string username, string password)
    {
        // 检查用户名是否已存在
        if (await _dbContext.Users.AnyAsync(u => u.Username == username))
        {
            return false; // 用户名已存在
        }

        // 生成哈希和盐
        PasswordHasher.CreatePasswordHash(password, out var hash, out var salt);

        // 保存用户
        var user = new User
        {
            Username = username,
            PasswordHash = hash,
            PasswordSalt = salt
        };

        _dbContext.Users.Add(user);
        await _dbContext.SaveChangesAsync();

        return true;
    }
}

登录验证功能实现

扩展AuthService添加登录验证:

public async Task<User?> LoginAsync(string username, string password)
{
    var user = await _dbContext.Users.FirstOrDefaultAsync(u => u.Username == username);
    if (user == null)
    {
        return null; // 用户不存在
    }

    // 验证密码哈希
    if (!PasswordHasher.VerifyPasswordHash(password, user.PasswordHash, user.PasswordSalt))
    {
        return null; // 密码错误
    }

    return user; // 验证成功,返回用户信息
}

关键注意事项

  • 绝不存储明文密码:仅保存哈希值和盐,即使数据库泄露,攻击者也无法直接获取用户密码。
  • 随机盐必须唯一:每个用户的盐独立生成,避免彩虹表攻击。
  • 迭代次数按需调整:根据服务器性能平衡安全性与响应速度,当前推荐10000+次迭代。
  • 添加密码强度校验:注册时验证密码长度、字符组合,降低弱密码被破解风险。
  • 避免计时攻击:使用CryptographicOperations.FixedTimeEquals对比哈希值,防止攻击者通过响应时间差异猜测哈希信息。

内容的提问来源于stack exchange,提问作者MogliMehmet

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 00:56:19