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

Asp.Net Core Identity中GenerateChangePhoneNumberTokenAsync未生成AspNetUserTokens记录问题

核心原因:两个令牌生成方法的底层实现逻辑完全不同

1. 邮箱确认令牌不需要持久化的原因

GenerateEmailConfirmationTokenAsync默认使用DataProtectorTokenProvider实现,生成的是加密自包含长令牌,令牌本身已经嵌入了用户ID、令牌用途、过期时间等所有校验所需信息,验证时直接解密校验内容即可,全程不需要操作AspNetUserTokens表,所以你看不到存储记录也能正常验证成功。

2. 手机号变更令牌不会写入AspNetUserTokens表的原因

GenerateChangePhoneNumberTokenAsync默认使用PhoneNumberTokenProvider实现,它基于TOTP(基于时间的一次性密码算法)生成6位数字短令牌,计算规则完全依赖用户的SecurityStamp、待变更的手机号、固定时间窗口三个要素,不需要额外持久化存储,设计上就不会往AspNetUserTokens表写入数据,表中无记录是正常现象。


手机号验证失败的常见排查方向

既然该类型令牌不需要持久化,验证失败和表中无记录无关,优先检查以下问题:

  • 校验方法参数不匹配:验证时必须调用VerifyChangePhoneNumberTokenAsync(user, 提交的令牌, 待验证的手机号),传入的手机号必须和生成令牌时传入的手机号完全一致,多一个空格、区号格式不同都会导致校验失败。
  • 超出有效时间窗口:默认TOTP令牌的有效时间是3分钟,生成后超过这个时间再验证就会失效,可通过配置PhoneNumberTokenProvider的TokenLifespan调整有效时长。
  • 生成令牌后用户安全戳被修改:如果生成令牌后你又调用了UpdateSecurityStampAsync、修改密码等会触发SecurityStamp更新的操作,所有之前生成的基于安全戳的令牌都会全部失效。

可选:手动持久化手机号令牌到AspNetUserTokens表

如果你的业务场景需要持久化存储令牌,可以在生成令牌后手动调用SetAuthenticationTokenAsync写入表中:

private async Task SendPhoneNumberTokenAsync(ApplicationUser user)
{
    if(user == null || string.IsNullOrEmpty(user.PhoneNumber) || user.PhoneNumberConfirmed)
        return;

    var token = await _userManager.GenerateChangePhoneNumberTokenAsync(user, user.PhoneNumber);
    // 手动写入AspNetUserTokens表
    await _userManager.SetAuthenticationTokenAsync(user, "PhoneProvider", "ChangePhoneNumberToken", token);

    // Send SMS
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 07:54:05