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

调用Login方法时AccountController抛出HS256密钥长度异常

解决ASP.NET Core 6中JWT HS256算法密钥长度不足的异常

我正在阅读一本基于ASP.NET Core 6的书籍,目前内容都不错,但在学习身份认证与授权章节时遇到了异常。

AccountController中的Register方法可正常将用户记录写入SQL的AspNetUsers表,但调用Login方法时抛出如下异常:

System.ArgumentOutOfRangeException: 'IDX10720: Unable to create KeyedHashAlgorithm for algorithm 'HS256', the key size must be greater than: '256' bits, key has '216' bits

相关代码

namespace MyBGList.Controllers
{
    [Route("[controller]/[action]")]
    [ApiController]
    public class AccountController : ControllerBase
    {
        private readonly ApplicationDbContext _context;
        private readonly ILogger<AccountController> _logger;
        private readonly IConfiguration _configuration;
        private readonly UserManager<ApiUser> _userManager;
        private readonly SignInManager<ApiUser> _signInManager;

        public AccountController(ApplicationDbContext context,
                                 ILogger<AccountController> logger,
                                 IConfiguration configuration,
                                 UserManager<ApiUser> userManager,
                                 SignInManager<ApiUser> signInManager)
        {
            _context = context;
            _logger = logger;
            _configuration = configuration;
            _userManager = userManager;
            _signInManager = signInManager;
        }

        //[ResponseCache(CacheProfileName = "NoCache")]
        [HttpPost]
        public async Task<ActionResult> Register(RegisterDTO input)
        {
            try
            {
                if (ModelState.IsValid)
                {
                    var newUser = new ApiUser();
                    newUser.UserName = input.UserName;
                    newUser.Email = input.Email;

                    var result = await _userManager.CreateAsync(newUser, input.Password);
                    
                    if (result.Succeeded)
                    {
                        _logger.LogInformation("User {userName} ({email}) has been created.", newUser.UserName, newUser.Email);
                        
                        return StatusCode(201,$"User '{newUser.UserName}' has been created.");
                    }
                    else
                        throw new Exception(string.Format("Error: {0}", string.Join(" ", result.Errors.Select(e => e.Description))));
                }
                else
                {
                    var details = new ValidationProblemDetails(ModelState);
                    details.Type = "https://tools.ietf.org/html/rfc7231#section-6.5.1";
                    details.Status = StatusCodes.Status400BadRequest;

                    return new BadRequestObjectResult(details);
                }
            }
            catch (Exception e)
            {
                var exceptionDetails = new ProblemDetails();
                exceptionDetails.Detail = e.Message;
                exceptionDetails.Status = StatusCodes.Status500InternalServerError;
                exceptionDetails.Type = "https://tools.ietf.org/html/rfc7231#section-6.6.1";

                return StatusCode(StatusCodes.Status500InternalServerError, exceptionDetails);
            }
        }

        //[ResponseCache(CacheProfileName = "NoCache")]
        [HttpPost]
        public async Task<ActionResult> Login(LoginDTO input)
        {
            try
            {
                if (ModelState.IsValid)
                {
                    var user = await _userManager.FindByNameAsync(input.UserName);

                    if (user == null || !await _userManager.CheckPasswordAsync(user, input.Password))
                    {
                        throw new Exception("Invalid login attempt.");
                    }
                    else
                    {
                        var signingCredentials = new SigningCredentials(
                            new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["JWT:SigningKey"])), SecurityAlgorithms.HmacSha256);

                        var claims = new List<Claim>();

                        claims.Add(new Claim(ClaimTypes.Name, user.UserName));

                        var jwtObject = new JwtSecurityToken(issuer: _configuration["JWT:Issuer"],
                                                             audience: _configuration["JWT:Audience"],
                                                             claims: claims,
                                                             expires: DateTime.Now.AddSeconds(300),
                                                             signingCredentials: signingCredentials);

                        // 此处抛出异常
                        var jwtString = new JwtSecurityTokenHandler().WriteToken(jwtObject);

                        return StatusCode(StatusCodes.Status200OK, jwtString);
                    }
                }
                else
                {
                    var details = new ValidationProblemDetails(ModelState);
                    details.Type = "https://tools.ietf.org/html/rfc7231#section-6.5.1";
                    details.Status = StatusCodes.Status400BadRequest;
                    
                    return new BadRequestObjectResult(details);
                }
            }
            catch (Exception e)
            {
                var exceptionDetails = new ProblemDetails();
                
                exceptionDetails.Detail = e.Message;
                exceptionDetails.Status = StatusCodes.Status401Unauthorized;
                exceptionDetails.Type = "https://tools.ietf.org/html/rfc7231#section-6.6.1";
                return StatusCode(StatusCodes.Status401Unauthorized, exceptionDetails);
            }
        }
    }
}

机密文件内容

{
  "ConnectionStrings": {
    "DefaultConnection": "Server=MyServer\\SQLEXPRESS;Database=MyBGList;User Id=MyBGListUser;Password=happy;Integrated Security=False;MultipleActiveResultSets=True; TrustServerCertificate=True"
  },
  "JWT": {
    "Issuer": "MyBGList",
    "Audience": "MyBGList",
    "SigningKey": "MyVeryOwnTestSigningKey123$"
  }
}

问题原因及解决方案

原因

异常提示明确说明:HS256(HMAC-SHA256)算法要求密钥长度至少为256位(32字节),而当前使用的密钥MyVeryOwnTestSigningKey123$经UTF-8编码后仅27字节(216位),不满足算法最低要求。

解决步骤

  1. 生成符合要求的密钥
    可通过以下方式生成32字节的随机密钥:

    • 使用在线随机字符串生成工具,选择32长度的字符串(或Base64编码的32字节数据)
    • 在PowerShell中执行命令:
      [Convert]::ToBase64String([System.Security.Cryptography.RandomNumberGenerator]::GetBytes(32))
      
    • 在.NET代码中生成:
      var keyBytes = new byte[32];
      using var rng = System.Security.Cryptography.RandomNumberGenerator.Create();
      rng.GetBytes(keyBytes);
      var signingKey = Convert.ToBase64String(keyBytes);
      
  2. 更新配置文件
    将机密文件中的JWT:SigningKey替换为新生成的密钥,示例:

    "JWT": {
      "Issuer": "MyBGList",
      "Audience": "MyBGList",
      "SigningKey": "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP" // 32字节示例密钥
    }
    
  3. 重启应用并测试
    重启ASP.NET Core应用后,重新调用Login接口即可正常生成JWT令牌。

额外建议

生产环境中请勿将密钥明文存储在配置文件,建议使用:

  • Azure Key Vault、AWS Secrets Manager等云服务密钥管理工具
  • 本地操作系统机密管理器(如Windows Credential Manager、Linux Vault)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 15:55:58