gpt4 book ai didi

c# - ASP.NET Identity 验证 ResetPassword token 是否已过期

转载 作者:行者123 更新时间:2023-11-30 12:20:30 25 4
gpt4 key购买 nike

在我的 API 中,我有 2 个端点,第一个端点生成电子邮件以重置密码表单(我使用 UserManager.GeneratePasswordResetTokenAsync 生成 token )。
第二个端点用于实际密码重置(我使用 UserManager.ResetPasswordAsync)。

我的要求是验证密码重置所需的 token 是否未过期。

在 GitHub 上搜索我找到了 this issue据我发现,这在设计上是不可能的。

然而,通过更深入的搜索,我发现 UserManager.ResetPasswordAsync内部使用来自 Microsoft.AspNet.Identity.Owin.DataProtectorTokenProviderValidateAsync

有了这个,我创建了这个扩展方法:

using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.Owin;
using System;
using System.Globalization;
using System.IO;
using System.Text;

namespace Api.Extensions
{
public enum TokenValidity
{
VALID,
INVALID,
INVALID_EXPIRED,
ERROR
}

public static class UserManagerExtensions
{
public static TokenValidity IsResetPasswordTokenValid<TUser, TKey>(this UserManager<TUser, TKey> manager, TUser user, string token) where TKey : IEquatable<TKey> where TUser : class, IUser<TKey>
{
return IsTokenValid(manager, user, "ResetPassword", token);
}

public static TokenValidity IsTokenValid<TUser, TKey>(this UserManager<TUser, TKey> manager, TUser user, string purpose, string token) where TKey : IEquatable<TKey> where TUser : class, IUser<TKey>
{
try
{
//not sure if this is needed??
if (!(manager.UserTokenProvider is DataProtectorTokenProvider<TUser, TKey> tokenProvider)) return TokenValidity.ERROR;

var unprotectedData = tokenProvider.Protector.Unprotect(Convert.FromBase64String(token));
var ms = new MemoryStream(unprotectedData);
using (var reader = ms.CreateReader())
{
var creationTime = reader.ReadDateTimeOffset();
var expirationTime = creationTime + tokenProvider.TokenLifespan;

var userId = reader.ReadString();
if (!String.Equals(userId, Convert.ToString(user.Id, CultureInfo.InvariantCulture)))
{
return TokenValidity.INVALID;
}

var purp = reader.ReadString();
if (!String.Equals(purp, purpose))
{
return TokenValidity.INVALID;
}

var stamp = reader.ReadString();
if (reader.PeekChar() != -1)
{
return TokenValidity.INVALID;
}

var expectedStamp = "";
//if supported get security stamp for user
if (manager.SupportsUserSecurityStamp)
{
expectedStamp = manager.GetSecurityStamp(user.Id);
}

if (!String.Equals(stamp, expectedStamp)) return TokenValidity.INVALID;

if (expirationTime < DateTimeOffset.UtcNow)
{
return TokenValidity.INVALID_EXPIRED;
}

return TokenValidity.VALID;
}
}
catch
{
// Do not leak exception
}
return TokenValidity.INVALID;
}
}

internal static class StreamExtensions
{
internal static readonly Encoding DefaultEncoding = new UTF8Encoding(false, true);

public static BinaryReader CreateReader(this Stream stream)
{
return new BinaryReader(stream, DefaultEncoding, true);
}

public static BinaryWriter CreateWriter(this Stream stream)
{
return new BinaryWriter(stream, DefaultEncoding, true);
}

public static DateTimeOffset ReadDateTimeOffset(this BinaryReader reader)
{
return new DateTimeOffset(reader.ReadInt64(), TimeSpan.Zero);
}

public static void Write(this BinaryWriter writer, DateTimeOffset value)
{
writer.Write(value.UtcTicks);
}
}
}

所以现在我可以添加这张支票了:

if (UserManager.IsResetPasswordTokenValid(user, model.Code) == TokenValidity.INVALID_EXPIRED)
{
return this.BadRequest("errorResetingPassword", "Link expired");
}

我的问题是:

1.有更简单的方法吗?
我的目的是向用户显示电子邮件中的链接已过期的信息,因为现在他只能看到重置密码出现问题。

2.如果没有这样做的内置方法,潜在的安全漏洞是什么?我使用我的扩展方法作为附加检查。如果我的方法返回 true,我仍然使用 ResetPasswordAsync

最佳答案

UserManager 具有您可以使用的 VerifyUserTokenAsync 和 VerifyUserToken 方法。

参见 Wouter's answer to the question "How can I check if a password reset token is expired?"了解更多详情。

所以你可以使用类似的东西

if (!UserManager.VerifyUserToken(userId, "ResetPassword", model.code)){
return this.BadRequest("errorResetingPassword", "Link expired");
}

关于c# - ASP.NET Identity 验证 ResetPassword token 是否已过期,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51519134/

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