C# dotnet core 3.1 API-UserManager.ConfirmMailAsync返回InvalidToken

C# dotnet core 3.1 API-UserManager.ConfirmMailAsync返回InvalidToken,c#,api,.net-core,C#,Api,.net Core,这个问题以前被问过好几次,但我发现至今没有一个答案有效 情况如下: 我正在向API添加电子邮件帐户确认功能。电子邮件已成功发送并到达。但是,方法userManager.confirmeailasync()总是返回false,错误为“InvalidToken”,即使在生成令牌时以及在用于确认时写入令牌时,它们是相同的 我尝试添加自定义电子邮件令牌提供程序,在发送和接收令牌时添加HttpUtility.UrlEncode和HttpUtility.UrlDecode方法,我在startup.cs类中从

这个问题以前被问过好几次,但我发现至今没有一个答案有效

情况如下:

我正在向API添加电子邮件帐户确认功能。电子邮件已成功发送并到达。但是,方法userManager.confirmeailasync()总是返回false,错误为“InvalidToken”,即使在生成令牌时以及在用于确认时写入令牌时,它们是相同的

我尝试添加自定义电子邮件令牌提供程序,在发送和接收令牌时添加HttpUtility.UrlEncode和HttpUtility.UrlDecode方法,我在startup.cs类中从services.AddDefaultIdentity切换到services.AddIdentity(因为我发现大多数在线实现都是这样做的),我尝试使用Base64Url编码

现在我已经没有主意了

以下是激活该方法的url(使用WebEncoders.Base64UrlEncode编码的令牌):

以下是用于发送电子邮件的方法:

private async Task<bool> SendConfirmationEmailToken(ApplicationUser user) {


        var emailToken = await _userManager.GenerateEmailConfirmationTokenAsync(user);

        Console.WriteLine(emailToken);
        byte[] tokenGeneratedBytes = Encoding.UTF8.GetBytes(emailToken);
        string codeEncoded = WebEncoders.Base64UrlEncode(tokenGeneratedBytes);
        emailToken = codeEncoded;

        var confirmationLink = Url.Action(nameof(ConfirmEmail), "ApplicationUser", new { token = emailToken, email = user.Email }, HttpContext.Request.Scheme);

        var message = new Message(new string[] { user.Email }.ToList(), "[BMC] - Confirm your E-mail adress", "Please confirm your e-mail address by clicking the following <a href=\"" + confirmationLink + "\">link</a>");

        _emailSender.SendEmail(message);

        return true;
    }
专用异步任务SendConfirmationMailToken(ApplicationUser用户){
var emailToken=wait_userManager.GenerateEmailConfirmationTokenAsync(用户);
Console.WriteLine(emailToken);
byte[]tokenGeneratedBytes=Encoding.UTF8.GetBytes(emailToken);
string codeEncoded=WebEncoders.Base64UrlEncode(tokenGeneratedBytes);
emailToken=编码;
var confirmationLink=Url.Action(nameof(ConfirmEmail),“ApplicationUser”,new{token=emailToken,email=user.email},HttpContext.Request.Scheme);
var message=new message(新字符串[]{user.Email}.ToList(),“[BMC]-确认您的电子邮件地址”,“请通过单击以下内容确认您的电子邮件地址”);
_emailSender.SendEmail(消息);
返回true;
}
用于确认电子邮件的方法:

    [HttpGet]
    [Route("ConfirmEmail/{token}/{email}")]
    public async Task<IActionResult> ConfirmEmail(string token, string email)
    {

        if (token == "" || email == "") {
            return BadRequest();
        }

        var codeDecodedBytes = WebEncoders.Base64UrlDecode(token);
        var codeDecoded = Encoding.UTF8.GetString(codeDecodedBytes);
        token = codeDecoded;

        Console.WriteLine(token);

        var user = await _userManager.FindByEmailAsync(email);
        //token = HttpUtility.UrlDecode(token);

        if (user == null)
        {
            return NotFound(new { isUserFound = false });
        }

        var result = await _userManager.ConfirmEmailAsync(user, token);

        if (result.Succeeded == false)
        {
            return BadRequest(new { isTokenValid = false });
        }

        return Ok(new { isEmailConfirmed = true });
    }
[HttpGet]
[路由(“确认邮件/{token}/{email}”)]
公共异步任务确认邮件(字符串令牌、字符串电子邮件)
{
如果(令牌=“”| |电子邮件=“”){
返回请求();
}
var codedecatedbytes=WebEncoders.Base64UrlDecode(令牌);
var codeDecoded=Encoding.UTF8.GetString(codeDecodedBytes);
令牌=编码解码;
控制台写入线(令牌);
var user=await\u userManager.findbyemailsync(电子邮件);
//token=HttpUtility.UrlDecode(token);
if(user==null)
{
返回NotFound(new{isUserFound=false});
}
var result=await\u userManager.confirmemailsync(用户,令牌);
如果(result.successed==false)
{
返回BadRequest(新的{isTokenValid=false});
}
返回Ok(新的{isemailcomfixed=true});
}
startup.cs中的ConfigureServices方法

public void ConfigureServices(IServiceCollection services)
    {

        services.AddControllers();

        services.AddDbContext<BMCContext>(options => options.UseSqlServer(Configuration.GetConnectionString("BMCConnection")));

        //JWT Authentication
        var key = Encoding.UTF8.GetBytes(Configuration["ApplicationSettings:JwtSecret"].ToString());
        services.AddAuthentication(x =>
        {
            x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            x.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
        }).AddJwtBearer(x =>
        {
            x.RequireHttpsMetadata = false;
            x.SaveToken = true;
            x.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = new SymmetricSecurityKey(key),
                ValidateIssuer = false,
                ValidateAudience = false,
                ClockSkew = TimeSpan.Zero
            };
        });

        services.AddIdentity<ApplicationUser, IdentityRole>(
            options =>
            {
                options.Password.RequireDigit = false;
                options.Password.RequireNonAlphanumeric = false;
                options.Password.RequireUppercase = false;
                options.Password.RequiredLength = 5;
                options.User.AllowedUserNameCharacters = "aąäábcčćdďđeęéěfghiíjklłmnńňoøóöpqrřsšśtťuúüůvwxyýzžźżAĄÄÁBCČĆDĎĐEÉĚĘFGHIÍJKLŁMNŃŇOØÓÖPQRŘSŠŚTŤUÜŮÚVWXYÝZŽŹŻ0123456789ß-._@+";
                options.User.RequireUniqueEmail = true;
                options.SignIn.RequireConfirmedEmail = true;
            }
        )
            . AddEntityFrameworkStores<BMCContext>()
            .AddDefaultTokenProviders();

        var emailConfig = Configuration.GetSection("EmailConfiguration").Get<EmailConfiguration>();
        services.AddSingleton(emailConfig);
        services.AddScoped<IEmailSender, EmailSender>();

        ApplicationSettings applicationSettings = new ApplicationSettings();
        Configuration.GetSection("ApplicationSettings").Bind(applicationSettings);
        services.AddSingleton<ApplicationSettings>(applicationSettings);


    }
public void配置服务(IServiceCollection服务)
{
services.AddControllers();
services.AddDbContext(options=>options.UseSqlServer(Configuration.GetConnectionString(“BMCConnection”));
//JWT认证
var key=Encoding.UTF8.GetBytes(配置[“应用程序设置:JwtSecret”].ToString());
services.AddAuthentication(x=>
{
x、 DefaultAuthenticateScheme=JwtBearerDefaults.AuthenticationScheme;
x、 DefaultChallengeScheme=JwtBearerDefaults.AuthenticationScheme;
x、 DefaultScheme=JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(x=>
{
x、 RequireHttpsMetadata=false;
x、 SaveToken=true;
x、 TokenValidationParameters=新的Microsoft.IdentityModel.Tokens.TokenValidationParameters
{
ValidateSuersigningKey=true,
IssuerSigningKey=新对称性安全密钥(密钥),
validateisuer=false,
ValidateAudience=false,
时钟偏移=时间跨度0
};
});
服务附加性(
选项=>
{
options.Password.RequireDigit=false;
options.Password.RequireNonAlphanumeric=false;
options.Password.RequireUppercase=false;
options.Password.RequiredLength=5;
用户。用户。用户。用户。AllWeWeWeWeWeWeWeWeWeWeWeWeWeWeWeWeWeWeWeWeWeWeWeWeWeWeWeWeWeWeWeWeWeWeWeWeWeWeWeWeWeWeWeWeWeWe用户用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户名称名称名称名称名称名称。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户名称名称名称名称名称名称名称。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。用户。"zŽŹŻ0123456789ß-.@+";
options.User.RequireUniqueEmail=true;
options.SignIn.RequireConfirmedEmail=true;
}
)
.AddEntityFrameworkStores()
.AddDefaultTokenProviders();
var emailConfig=Configuration.GetSection(“EmailConfiguration”).Get();
services.AddSingleton(emailConfig);
services.addScope();
ApplicationSettings ApplicationSettings=新的ApplicationSettings();
Configuration.GetSection(“应用程序设置”).Bind(应用程序设置);
服务。添加单例(应用程序设置);
}

提前感谢您的帮助

经过大量测试,我终于找到了错误

错误是将错误数据发送到CreateAsync方法,这导致UserManager尝试创建用户两次,这反过来又导致确认令牌无效,因为它是为完全不同的用户生成的