当前位置: 首页 > 知识库问答 >
问题:

ASP.NET Identity 2.0随机无效令牌

充鑫鹏
2023-03-14
IdentityResult result = manager.Create(user, "Password134567");
if (result.Succeeded)
{
    var provider = new DpapiDataProtectionProvider("WebApp2015");
    UserManager<User> userManager = new UserManager<User>(new UserStore<User>());
    userManager.UserTokenProvider = new DataProtectorTokenProvider<User>(provider.Create(user.Id));
    manager.UserTokenProvider = new DataProtectorTokenProvider<User>(provider.Create("ConfirmUser"));

    var emailInfo = new Email();

    string code = HttpUtility.UrlEncode(Context.GetOwinContext().GetUserManager<ApplicationUserManager>().GenerateEmailConfirmationToken(user.Id));
    string callbackUrl = IdentityHelper.GetUserConfirmationRedirectUrl(code, user.Id, Request);

    if (email.IndexOf("@") != -1)
    {
        if (assignedId == 0)
        {
            lblError.Text = "There was an error adding this user";
            return;
        }
        string emailcontent = emailInfo.GetActivationEmailContent(assignedId, callbackUrl, userRole);
        string subject = emailInfo.Subject;
        if (string.IsNullOrEmpty(subject))
        {
            subject = "Your Membership";
        }
        Context.GetOwinContext()
               .GetUserManager<ApplicationUserManager>()
               .SendEmail(user.Id, subject, emailcontent);

        if (user.EmailConfirmed)
        {
            IdentityModels.IdentityHelper.SignIn(manager, user, isPersistent: false);
            IdentityHelper.RedirectToReturnUrl(Request.QueryString["ReturnUrl"], Response);
        }
        else
        {
            ErrorMessage.ForeColor = Color.Green;
            ErrorMessage.Text = "An email has been sent to the user, once they verify their email they are ready to login.";
        }
    }
    else
    {
        ErrorMessage.ForeColor = System.Drawing.Color.Green;
        ErrorMessage.Text = "User has been created.";
    }

    var ra = new RoleActions();
    ra.AddUserToRoll(txtEmail.Text, txtEmail.Text, userRole);
}
else
{
    ErrorMessage.Text = result.Errors.FirstOrDefault();
}
protected void Page_Load(object sender, EventArgs e)
{
    var code = IdentityHelper.GetCodeFromRequest(Request);
    var userId = IdentityHelper.GetUserIdFromRequest(Request);
    if (code != null && userId != null)
    {
        var manager = Context.GetOwinContext()
                             .GetUserManager<ApplicationUserManager>();
        var confirmId = manager.FindById(userId);
        if (confirmId != null)
        {
            var result = manager.ConfirmEmail(userId, HttpUtility.UrlDecode(code));
            if (result.Succeeded)
            {
                return;
            }
            else
            {
                lblError.Text = result.Errors.FirstOrDefault();
                txtNewPassword.TextMode= TextBoxMode.SingleLine;
                txtNewPassword.Text = "Error contact support";
                txtNewPassword2.TextMode= TextBoxMode.SingleLine;
                txtNewPassword2.Text = result.Errors.FirstOrDefault();
                txtNewPassword.Enabled = false;
                txtNewPassword2.Enabled = false;
                imageButton1.Enabled = false;
            }
        }
        else
        {
            lblError.Text = "Account Does Not Exist";
            imageButton1.Enabled = false;
        }
    }
}

共有1个答案

鞠侯林
2023-03-14

我为您创建了一个精简的演示项目。它在这里的GitHub上托管,在这里的Azure上直播。它按照设计的方式工作(请参见Azure网站的编辑),使用了与您使用的类似但不完全相同的方法。

它从这个教程开始,然后我删除了这个NuGet演示代码附带的cruft:

Install-Package -Prerelease Microsoft.AspNet.Identity.Samples 

出于您的目的,我的演示代码比NuGet示例更相关,因为它只关注令牌的创建和验证。特别要看一下这两个文件:

public partial class Startup
{
    public static IDataProtectionProvider DataProtectionProvider 
    { 
        get; 
        private set; 
    }

    public void ConfigureAuth(IAppBuilder app)
    {
        DataProtectionProvider = 
            new DpapiDataProtectionProvider("WebApp2015");

        // other code removed
    }
}
userManager.UserTokenProvider = 
    new DataProtectorTokenProvider<User>(
        Startup.DataProtectionProvider.Create("UserToken"));

DataProtectorTokenProvider.create(string[]composes)方法接受composes参数。以下是MSDN对此的看法:

目的。用于确保受保护的数据只能出于正确的目的而不受保护的额外熵。

当您创建用户code时,您(至少)使用了两种不同的目的:

    null
userManager.UserTokenProvider = 
    new DataProtectorTokenProvider<User>(provider.Create(user.Id));

manager.UserTokenProvider = 
    new DataProtectorTokenProvider<User>(provider.Create("ConfirmUser"));

string code = Context
    .GetOwinContext()
    .GetUserManager<ApplicationUserManager ()      
    .GenerateEmailConfirmationToken(user.Id)

验证代码时,可能使用了错误的目的。您在何处为用于确认电子邮件的ApplicationUserManager分配UserTokenProvider?它的目的论点必须是相同的!

var manager = Context.GetOwinContext()
                  .GetUserManager<ApplicationUserManager>();

var result = manager.ConfirmEmail(userId, HttpUtility.UrlDecode(code));

令牌很有可能是无效的,因为有时创建时使用的UserTokenProvider目的与验证时使用的目的不同。

为什么有时会这样?彻底搜索代码,查找分配给UserTokenProvider的所有位置。也许您会在意外的地方重写它(例如在属性中或在IdentityConfig.cs文件中),以便它看起来是随机的。

manager.UserTokenProvider = 
    new DataProtectorTokenProvider<ApplicationUser>
      (dataProtectionProvider.Create("WebApp2015"))
      {                    
         TokenLifespan = TimeSpan.FromHours(3000)
      };
    null

请注意,我删除了很多代码,只关注您的令牌创建。

// 1. 
IdentityResult result = manager.Create(user, "Password134567");

if (result.Succeeded)
{
    var provider = new DpapiDataProtectionProvider("WebApp2015");

    // 2. 
    UserManager<User> userManager = 
        new UserManager<User>(new UserStore<User>());

    userManager.UserTokenProvider = 
        new DataProtectorTokenProvider<User>(provider.Create(user.Id));

    // 3.
    manager.UserTokenProvider = 
        new DataProtectorTokenProvider<User>(provider.Create("ConfirmUser"));

    // 4. 
    string raw = Context.GetOwinContext()
                 .GetUserManager<ApplicationUserManager>()
                 .GenerateEmailConfirmationToken(user.Id)

    // remaining code removed
}

我想知道我们是否可以简化上述操作,只使用一个UserManager实例,如下所示。

// 1. 
IdentityResult result = manager.Create(user, "Password134567");

if (result.Succeeded)
{
    var provider = new DpapiDataProtectionProvider("WebApp2015");

    manager.UserTokenProvider = 
        new DataProtectorTokenProvider<User>(provider.Create(user.Id));

    // 3.
    var provider = provider.Create("ConfirmUser");
    manager.UserTokenProvider = 
        new DataProtectorTokenProvider<User>(provider);

    // 4. 
    string raw = manager.GenerateEmailConfirmationToken(user.Id);

    // remaining code removed
}

如果使用此方法,请确保在确认电子邮件期间使用相同的“验证者”目的参数。

    null
var code01 = CreateCode();
var code02 = UrlEncode(code01);
var request = CreateTheRequest(code02);
var response = GetTheResponse();
var code03 = GetTheCode(response);
var code04 = UrlDecode(code03);
Assert.AreEquals(code01, code04);

运行以上1万次,确保不存在任何问题。

我强烈怀疑问题在于在创建令牌时使用了一个ophyses参数,而在确认时使用了另一个参数。只有一个目的,你可能会没事。

  1. 使用SqlCompact而不是localdb.
  2. 使用app.getDataProtectionProvider()而不是DPAPIDataProtectionProvider,因为Dpapi不能用于web场。
 类似资料:
  • 我用python编写了代码,定期获取特定股票代码的数据。 我面临的问题是,这段代码大部分时间都运行良好。但是,偶尔,它会抛出一个错误,说“无效的应用编程接口调用”。 这种情况并非总是发生。也许一次就是3-4个电话。有时在第一个电话里。 我绝不会修改任何东西 怎么回事啊?

  • 问题内容: 尝试为变量分配值时出现问题。当我尝试按以下顺序将日期作为元组或列表时,问题就会出现: 为什么要打apping? 我如何解决它? 令牌在Python中是什么意思? 问题答案: 在Python 3中,数字前导零是不允许的。例如: 等是不允许的,但应改为和。 但是,在Python 2中,前导零表示该数字是一个 八进制数 (以8为底),因此,或分别表示和,并且以八进制表示,但由于它不是有效的八

  • 问题内容: 我有以下代码从PHP 数组中选取元素: 给定一个大数组,但只有几个元素(例如out ),这相对较慢,因此我想对其进行优化,以使并非所有元素都必须改组。这些值必须是唯一的。 我正在寻找性能最好的替代产品。我们可以假设它没有重复项并且被索引了。 问题答案: 这将提供5个元素,而且没有重复项,而且很快。密钥将被保留。 注意:您必须确保$ array包含5个或更多的元素,或者添加某种检查以防止

  • 问题内容: 在这个问题中,Erik需要在Node.js中生成一个安全的随机令牌。有一种生成随机缓冲区的方法。但是,node中的base64编码不是网址安全的,它包含和而不是和。因此,我发现生成这种令牌的最简单方法是 有没有更优雅的方式? 问题答案: 尝试crypto.randomBytes(): “十六进制”编码在节点v0.6.x或更高版本中有效。

  • 问题内容: 我有一种方法,它使用随机样本来近似计算。这种方法被称为数百万次,因此非常重要的是选择随机数的过程必须高效。 我不确定java到底有多快,但是我的程序似乎并没有像我期望的那样受益。 选择随机数时,我将执行以下操作(半伪代码): 现在,这显然具有最坏的最坏情况下的运行时间,因为理论上随机函数可以为永恒添加重复的数字,从而永远停留在while循环中。但是,数字是从{0..45}中选择的,因此

  • 但是,一旦我们更改命令(更改位置fontfile=with text= 我得到以下错误 [Parsed_drawtext_0@02d88a80]无法加载字体“C”:无法找到匹配的字体