[英]AspNetCore.Identity.UserManager[9] VerifyUserTokenAsync() "code": "InvalidToken",
I am making api in .net 5 and implementing sending email confirmation after succesful registration.我正在 .net 5 中制作 api 并在成功注册后实现发送 email 确认。 This one is killing me and can't see the reason why it returns
Invalid Token
.这个正在杀死我,看不到它返回
Invalid Token
的原因。
So here's my code:所以这是我的代码:
Startup.cs启动.cs
services.AddAuthentication
...
...
...
services.AddIdentityCore<User>(config =>
{
config.SignIn.RequireConfirmedEmail = true;
}).AddEntityFrameworkStores<WorkoutDbContext>()
.AddDefaultTokenProviders();
EmailHelper.cs电子邮件助手.cs
public class EmailHelper
{
public bool SendEmail(string userEmail, string confirmationLink)
{
MailMessage mailMessage = new MailMessage();
mailMessage.From = new MailAddress("noreply@*********.io");
mailMessage.To.Add(new MailAddress(userEmail));
mailMessage.Subject = "Confirm your email";
mailMessage.IsBodyHtml = false;
mailMessage.Body = confirmationLink;
SmtpClient client = new SmtpClient();
client.UseDefaultCredentials = false;
client.Credentials = new System.Net.NetworkCredential("noreply@*********.io", "super secret password");
client.Host = "host";
client.Port = 000;
client.EnableSsl = false;
client.DeliveryFormat = (SmtpDeliveryFormat)SmtpDeliveryMethod.Network;
try
{
client.Send(mailMessage);
return true;
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
// log exception
}
return false;
}
}
AccountService.cs AccountService.cs
public async void RegisterUser(RegisterUserDto dto)
{
var uniqueId = Guid.NewGuid().ToString()[..8];
var newUser = new User()
{
Name = dto.Name,
LastName = dto.LastName,
Email = dto.Email,
EmailConfirmed = false,
UniqeId = uniqueId,
RegistrationDate = DateTime.Now,
Active = false,
RoleId = dto.RoleId
};
var hashedPassword = _passwordHasher.HashPassword(newUser, dto.Password);
newUser.Password = hashedPassword;
newUser.NormalizedEmail = dto.Email;
_context.Add(newUser);
_context.SaveChanges();
var user = await _userManager.FindByEmailAsync(newUser.Email);
if(user != null)
{
EmailHelper emailHelper = new EmailHelper();
var token = HttpUtility.UrlEncode(await _userManager.GenerateEmailConfirmationTokenAsync(newUser));
var confirmationLink = "http://localhost:5000/confirmEmail?token=" + token + "&email=" + newUser.NormalizedEmail;
bool emailResponse = emailHelper.SendEmail(newUser.NormalizedEmail, confirmationLink);
}
}
User registration works fine.用户注册工作正常。 If email is not registered than registration fails.
如果 email 未注册,则注册失败。 Otherwise server return 200 as expected.
否则服务器按预期返回 200。 Confirmation link is sent to email provided during registration process.
确认链接发送至注册过程中提供的 email。 So till now works as expected.
所以直到现在按预期工作。
EmailController.cs电子邮件控制器.cs
[HttpGet]
public async Task<IdentityResult> ConfirmEmail([FromQuery]string token, [FromQuery] string email)
{
var user = await _userManager.FindByEmailAsync(email);
var result = await _userManager.ConfirmEmailAsync(user, token);
if (result.Succeeded) { return IdentityResult.Success; }
else { return (IdentityResult) result; }
}
Problem start when clicking on activation link - it throws warn: Microsoft.AspNetCore.Identity.UserManager[9] VerifyUserTokenAsync() "code": "InvalidToken",
So activation link is sent, it checks if user !== null
and than goes to conditional statement and triggers EmailHelper which sends link to inbox correctly.单击激活链接时出现问题 - 它会引发
warn: Microsoft.AspNetCore.Identity.UserManager[9] VerifyUserTokenAsync() "code": "InvalidToken",
所以激活链接已发送,它会检查user !== null
并且比去到条件语句并触发正确发送链接到收件箱的EmailHelper 。
...BUT ...但
When I try to console user - it's empty, nothing shows in console.当我尝试安慰用户时 - 它是空的,控制台中没有显示任何内容。 Database is updated and user is saved in DB and it's visible and accessible.
数据库已更新,用户保存在数据库中,并且可见且可访问。 In EmailController.cs it does not return user
在EmailController.cs它不返回用户
var user = await _userManager.FindByEmailAsync(email);
// if I try to console it it shows nothing - empty(not NULL)
If I try to send serialized user data to inbox instead of sending activation link it sends correct data from DB.如果我尝试将序列化的用户数据发送到收件箱而不是发送激活链接,它会从 DB 发送正确的数据。
So to sum up:所以总结一下:
var user = await _userManager.FindByEmailAsync(newUser.Email); if(user != null)
var user = await _userManager.FindByEmailAsync(newUser.Email); if(user != null)
var user = await _userManager.FindByEmailAsync(newUser.Email); if(user != null)
makes user NOT null send allows to send email var user = await _userManager.FindByEmailAsync(newUser.Email); if(user != null)
使用户 NOT null 发送允许发送 email And this is killing me and do not know why checking if user exists gives true but trying to access via await _userManager.FindByEmailAsync(newUser.Email);
这让我很生气,不知道为什么检查用户是否存在给出了 true 但尝试通过
await _userManager.FindByEmailAsync(newUser.Email);
访问gives no user(nothing)?没有用户(什么都没有)? I tried also (in EmailController )
_context.Users.FirstOrDefault(u => u.NormalizedEmail == email)
but the result is the same - cannot get user from DB and returns我也试过(在EmailController中)
_context.Users.FirstOrDefault(u => u.NormalizedEmail == email)
但结果是一样的 - 无法从数据库中获取用户并返回
Microsoft.AspNetCore.Identity.UserManager[9]
VerifyUserTokenAsync() failed with purpose: EmailConfirmation for user.
UPDATE IdentityResult output更新身份结果 output
{
"succeeded": false,
"errors": [
{
"code": "InvalidToken",
"description": "Invalid token."
}
]
}
UPDATE #2更新#2
When I serialize user
and try to display in console it actually shows correct user data as a string.当我序列化
user
并尝试在控制台中显示时,它实际上将正确的用户数据显示为字符串。 The problem seems to be that neither var user = await _userManager.FindByEmailAsync(email);
问题似乎是
var user = await _userManager.FindByEmailAsync(email);
nor var user= _context.Users.FirstOrDefault(u => u.Email == email);
也不是
var user= _context.Users.FirstOrDefault(u => u.Email == email);
does not return user that can be verified.不返回可以验证的用户。
UPDATE #3更新#3
No IUserTwoFactorTokenProvider<TUser> named 'xxxx' is registered. System.NotSupportedException: No IUserTwoFactorTokenProvider<TUser> named 'xxxx' is registered.
But AddDefaultTokenProviders()
was implemented in Startup.cs Even tried config.Tokens.EmailConfirmationTokenProvider = TokenOptions.DefaultEmailProvider;
但是在 Startup.cs 中实现了
AddDefaultTokenProviders()
甚至尝试config.Tokens.EmailConfirmationTokenProvider = TokenOptions.DefaultEmailProvider;
or config.Tokens.ProviderMap.Add("Default", new TokenProviderDescriptor(typeof(IUserTwoFactorTokenProvider<User>)));
或
config.Tokens.ProviderMap.Add("Default", new TokenProviderDescriptor(typeof(IUserTwoFactorTokenProvider<User>)));
but the result is the same.但结果是一样的。
I was working on the solution for past few days but finally found a solution!过去几天我一直在研究解决方案,但终于找到了解决方案!
Since I am using IdentityUser
but my User
model did not contain table columns from Identity it cause problem, most likely because that security stamp column was not present.由于我使用的是
IdentityUser
但我的User
model 不包含来自 Identity 的表列,因此会导致问题,很可能是因为该安全标记列不存在。
What I did was to include table columns from IdentityUser
.我所做的是包含来自
IdentityUser
的表列。
I have also included我也包括了
services.AddIdentityCore<User>(config =>
{
config.SignIn.RequireConfirmedEmail = true;
config.Tokens.EmailConfirmationTokenProvider = TokenOptions.DefaultEmailProvider; <--- this line!!
}).AddEntityFrameworkStores<WorkoutDbContext>()
.AddDefaultTokenProviders();
Also in EmailController.cs in ConfirmEmail
I had to decode
token because I was encoding
this with HttpUtility.Encode
when egenrating.同样在
ConfirmEmail
的EmailController.cs中,我必须decode
令牌,因为我在生成时使用HttpUtility.Encode
对其进行encoding
。 var tokenDecode = HttpUtility.UrlDecode(token);
Than I checked with VerifyUserTokenAsync
which returned true
.比我检查返回
true
的VerifyUserTokenAsync
。 After that I only received confirmation error when email was clicked that Username '' is invalid. Username can have only letters and number.
之后,我只在单击 email 时收到确认错误,即
Username '' is invalid. Username can have only letters and number.
Username '' is invalid. Username can have only letters and number.
What I also did was generating userName
containing only letters and numbers from email that was used for registration and assigning it to UserName
column in DB set.我还做的是生成仅包含来自
userName
的字母和数字的用户名,用于注册并将其分配给数据库集中的UserName
名列。
After that when email was sent and clicked it returned IdentityResult.Success
之后,当发送 email 并单击它返回
IdentityResult.Success
Damn.该死。 It was a long way home: :)
回家的路很长::)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.