gpt4 book ai didi

azure - ASP.NET Core 2.2 - 密码重置在 Azure 上不起作用( token 无效)

转载 作者:行者123 更新时间:2023-12-03 04:42:32 27 4
gpt4 key购买 nike

我有一个 ASP.NET Core 2.2 应用程序在 Azure Web App 的多个实例上运行;它使用 EF Core 2.2ASP.NET Identity

除了密码重置流程外,一切正常,用户在每封电子邮件中都会收到一个带有 token 的链接,并且需要通过单击该链接来选择新密码。它在本地运行良好,但在 Azure 上它总是失败并出现“无效 token ”错误

token 根据需要进行 HTML 编码和解码;我进行了检查以确保它们与数据库中的匹配; URL 编码不是问题。

我已配置 DataProtection 将 key 存储到 Azure Blob 存储,但无济于事。 key 确实存储在 blob 存储中,但我仍然收到“无效 token ”错误

这是我在 Startup.cs 上的设置:

public void ConfigureServices(IServiceCollection services)
{
// This needs to happen before "AddMvc"
// Code for this method shown below
AddDataProtecion(services);

services.AddDbContext<MissDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

var sp = services.BuildServiceProvider();

services.ConfigureApplicationCookie(x =>
{
x.Cookie.Name = ".MISS.SharedCookie";
x.ExpireTimeSpan = TimeSpan.FromHours(8);
// We need to set the cookie's DataProtectionProvider to ensure it will get stored in the azure blob storage
x.DataProtectionProvider = sp.GetService<IDataProtectionProvider>();
});

services.AddIdentity<ApplicationUser, ApplicationRole>()
.AddEntityFrameworkStores<MissDbContext>()
.AddDefaultTokenProviders();


// https://tech.trailmax.info/2017/07/user-impersonation-in-asp-net-core/
services.Configure<SecurityStampValidatorOptions>(options =>
{
options.ValidationInterval = TimeSpan.FromMinutes(10);
options.OnRefreshingPrincipal = context =>
{
var originalUserIdClaim = context.CurrentPrincipal.FindFirst("OriginalUserId");
var isImpersonatingClaim = context.CurrentPrincipal.FindFirst("IsImpersonating");
if (isImpersonatingClaim?.Value == "true" && originalUserIdClaim != null)
{
context.NewPrincipal.Identities.First().AddClaim(originalUserIdClaim);
context.NewPrincipal.Identities.First().AddClaim(isImpersonatingClaim);
}
return Task.FromResult(0);
};
});

// some more initialisations here
}

这是 AddDataProtection 方法:

/// <summary>
/// Add Data Protection so that cookies don't get invalidated when swapping slots.
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
void AddDataProtecion(IServiceCollection services)
{
var sasUrl = Configuration.GetValue<string>("DataProtection:SaSUrl");
var containerName = Configuration.GetValue<string>("DataProtection:ContainerName");
var applicationName = Configuration.GetValue<string>("DataProtection:ApplicationName");
var blobName = Configuration.GetValue<string>("DataProtection:BlobName");
var keyIdentifier = Configuration.GetValue<string>("DataProtection:KeyVaultIdentifier");

if (sasUrl == null || containerName == null || applicationName == null || blobName == null)
return;

var storageUri = new Uri($"{sasUrl}");

var blobClient = new CloudBlobClient(storageUri);

var container = blobClient.GetContainerReference(containerName);
container.CreateIfNotExistsAsync().GetAwaiter().GetResult();

applicationName = $"{applicationName}-{Environment.EnvironmentName}";
blobName = $"{applicationName}-{blobName}";

services.AddDataProtection()
.SetApplicationName(applicationName)
.PersistKeysToAzureBlobStorage(container, blobName);
}

我还尝试将 key 保存到 DbContext,但结果是相同的: key 已存储,但在尝试重置密码时,我仍然收到无效 token 消息,Every。单例的。时间。

请求密码重置方法

public async Task RequestPasswordReset(string emailAddress, string ip, Request httpRequest) 
{
var user = await _userManager.FindByEmailAsync(emailAddress);

var resetToken = await _userManager.GeneratePasswordResetTokenAsync(user);

var resetRequest = new PasswordResetRequest
{
CreationDate = DateTime.Now,
ExpirationDate = DateTime.Now.AddDays(1),
UserId = user.Id,
Token = resetToken,
IP = ip
};

_context.PasswordResetRequests.Add(resetRequest);
await _context.SaveChangesAsync();

await SendPasswordResetEmail(user, resetRequest, httpRequest);
}

重置密码方法

用户请求重置密码后,他们会收到一封包含链接和 token 的电子邮件;以下是我在用户单击该链接后尝试重置用户密码的方法:

public async Task<IdentityResult> ResetPassword(string token, string password) 
{
// NO PROBLEM HERE - The received token matches with the one in the Db
var resetRequest = await _context.PasswordResetRequests
.AsNoTracking()
.FirstOrDefaultAsync(x => x.Token == token);

var user = await _userManager.FindByIdAsync(resetRequest.UserId);

// PROBLEM - This method returns "Invalid Token"
var result = await _userManager.ResetPasswordAsync(user, resetRequest.Token, password);

if (result.Succeeded)
await SendPasswordChangedEmail(user);

return result;
}

正如我在代码注释中所述,请求中收到的 token 与数据库中生成的 token 相匹配,但 ResetPasswordAsync 会进行自己的 token 验证,但会失败。

任何帮助仍将不胜感激

最佳答案

这表明您的 token 是通过不同的方式生成的。你能试试这个吗?生成新 token :

var code = await UserManager.GeneratePasswordResetTokenAsync(resetRequest.UserId);

并重置密码:

var resetResult = await userManager.ResetPasswordAsync(resetRequest.UserId, code, password);

另一种情况是 token 的 HTML 编码不正确:

token = HttpUtility.UrlDecode(token) ;

下一种情况是 userManager 对于每个请求都必须是单例(或至少是 tokenProvider 类)。

这是源代码链接 https://github.com/aspnet/Identity/blob/rel/2.0.0/src/Microsoft.Extensions.Identity.Core/UserManager.cs#L29

手动 token 处理,以防由于将 token 存储到私有(private)变量而导致 token 提供者的不同实例:

private readonly Dictionary<string, IUserTwoFactorTokenProvider<TUser>> _tokenProviders =
new Dictionary<string, IUserTwoFactorTokenProvider<TUser>>();

可能会实现下一个代码:

  public override async Task<bool> VerifyUserTokenAsync(TUser user, string tokenProvider, string purpose, string token)
{
ThrowIfDisposed();
if (user == null)
{
throw new ArgumentNullException(nameof(user));
}
if (tokenProvider == null)
{
throw new ArgumentNullException(nameof(tokenProvider));
}
//should be overriden
// if (!_tokenProviders.ContainsKey(tokenProvider))
// {
// throw new
//NotSupportedException(string.Format(CultureInfo.CurrentCulture,
//Resources.NoTokenProvider, tokenProvider));
// }
// Make sure the token is valid
// var result = await _tokenProviders[tokenProvider].ValidateAsync(purpose, token, this, user);

// if (!result)
// {
// Logger.LogWarning(9, "VerifyUserTokenAsync() failed with //purpose: {purpose} for user {userId}.", purpose, await GetUserIdAsync(user));
// }
var resetRequest = await _context.PasswordResetRequests
.AsNoTracking()
.FirstOrDefaultAsync(x => x.Token == token);
if (resetRequest == null )
{
return IdentityResult.Failed(ErrorDescriber.InvalidToken());
}

// Make sure the token is valid
var result = resetRequest.IsValid();

if (!result)
{
Logger.LogWarning(9, "VerifyUserTokenAsync() failed with purpose: {purpose} for user {userId}.", purpose, await GetUserIdAsync(user));
}
return result;
}

关于azure - ASP.NET Core 2.2 - 密码重置在 Azure 上不起作用( token 无效),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56237459/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com