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

如何在Duende Identity Server中自定义密码哈希算法?

在Duende Identity Server中自定义密码哈希算法的实现

Duende Identity Server完全支持自定义密码哈希算法,因为它深度依赖ASP.NET Core Identity体系,而Identity本身允许通过替换IPasswordHasher<TUser>接口实现来自定义密码处理逻辑。以下是具体操作步骤:

1. 实现自定义的IPasswordHasher

创建一个类实现ASP.NET Core Identity的IPasswordHasher<TUser>接口(TUser是你的用户实体类,比如ApplicationUser),实现HashPassword和VerifyHashedPassword两个核心方法,写入你的自定义哈希逻辑(注意必须包含加盐逻辑,避免彩虹表攻击):

using Microsoft.AspNetCore.Identity;
using System.Security.Cryptography;
using System.Text;

public class CustomPasswordHasher : IPasswordHasher<ApplicationUser>
{
    public string HashPassword(ApplicationUser user, string password)
    {
        // 生成16字节的随机盐
        var saltBytes = new byte[16];
        using var rng = RandomNumberGenerator.Create();
        rng.GetBytes(saltBytes);
        var salt = Convert.ToBase64String(saltBytes);

        // 组合密码与盐并计算SHA256哈希
        var passwordBytes = Encoding.UTF8.GetBytes(password);
        var combinedBytes = passwordBytes.Concat(Convert.FromBase64String(salt)).ToArray();
        using var sha256 = SHA256.Create();
        var hashBytes = sha256.ComputeHash(combinedBytes);
        var hashedPassword = Convert.ToBase64String(hashBytes);

        // 返回盐与哈希值的组合字符串(用分隔符区分,便于后续验证)
        return $"{salt}:{hashedPassword}";
    }

    public PasswordVerificationResult VerifyHashedPassword(ApplicationUser user, string hashedPassword, string providedPassword)
    {
        // 拆分存储的盐与哈希值
        var parts = hashedPassword.Split(':');
        if (parts.Length != 2)
            return PasswordVerificationResult.Failed;

        var salt = parts[0];
        var storedHash = parts[1];

        // 计算输入密码的哈希值并对比
        var passwordBytes = Encoding.UTF8.GetBytes(providedPassword);
        var combinedBytes = passwordBytes.Concat(Convert.FromBase64String(salt)).ToArray();
        using var sha256 = SHA256.Create();
        var computedHash = Convert.ToBase64String(sha256.ComputeHash(combinedBytes));

        return computedHash == storedHash 
            ? PasswordVerificationResult.Success 
            : PasswordVerificationResult.Failed;
    }
}

2. 注册自定义哈希器到DI容器

在项目的依赖注入配置中(通常是Program.cs),注册你的自定义哈希器,覆盖默认的IPasswordHasher<TUser>实现:

builder.Services.AddScoped<IPasswordHasher<ApplicationUser>, CustomPasswordHasher>();

注意:此注册无需严格限定顺序,DI系统会自动优先使用你注册的自定义实现。

3. (可选)平滑迁移旧密码

如果之前已使用默认PasswordHasher存储了用户密码,切换自定义算法后旧密码会验证失败。可以修改VerifyHashedPassword方法,先尝试用默认算法验证,成功后标记需要重新哈希,后续在业务逻辑中更新用户密码:

public PasswordVerificationResult VerifyHashedPassword(ApplicationUser user, string hashedPassword, string providedPassword)
{
    // 先尝试默认哈希算法验证旧密码
    var defaultHasher = new PasswordHasher<ApplicationUser>();
    var defaultResult = defaultHasher.VerifyHashedPassword(user, hashedPassword, providedPassword);
    
    if (defaultResult == PasswordVerificationResult.Success)
    {
        // 旧密码验证成功,返回需要重新哈希的标记
        return PasswordVerificationResult.SuccessRehashNeeded;
    }

    // 自定义算法验证逻辑
    var parts = hashedPassword.Split(':');
    if (parts.Length != 2)
        return PasswordVerificationResult.Failed;

    var salt = parts[0];
    var storedHash = parts[1];
    var passwordBytes = Encoding.UTF8.GetBytes(providedPassword);
    var combinedBytes = passwordBytes.Concat(Convert.FromBase64String(salt)).ToArray();
    using var sha256 = SHA256.Create();
    var computedHash = Convert.ToBase64String(sha256.ComputeHash(combinedBytes));

    return computedHash == storedHash 
        ? PasswordVerificationResult.Success 
        : PasswordVerificationResult.Failed;
}

之后在用户登录的逻辑中,判断返回SuccessRehashNeeded时,调用UserManager.UpdateAsync更新用户的PasswordHash为新算法生成的值即可。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 01:47:01