简体   繁体   English

如何为 asp.net 核心中 GenerateUserTokenAsync 创建的令牌设置 TimeSpan?

[英]How to set TimeSpan for token that created by GenerateUserTokenAsync in asp.net core?

I have "Forgot Password" page in my project.我的项目中有“忘记密码”页面。 At this page, I create 6 digit number by using _userManager.GenerateUserTokenAsync(user, TokenOptions.DefaultPhoneProvider, "ResetPasswordTokenPurpose");在此页面上,我使用_userManager.GenerateUserTokenAsync(user, TokenOptions.DefaultPhoneProvider, "ResetPasswordTokenPurpose");创建了 6 位数字then send this code to user.然后将此代码发送给用户。 Now I want to set time span for this code that expire it after 2 minutes.现在我想为这段代码设置 2 分钟后过期的时间跨度。 I add a custom provider to the service container but It doesn't work for the code that created by GenerateUserTokenAsync .and also I don't want to set timeSpan that apply to all token.我向服务容器添加了一个自定义提供程序,但它不适用于由GenerateUserTokenAsync创建的代码。而且我不想设置适用于所有令牌的 timeSpan。 How can I set custom timeSpan for this?如何为此设置自定义 timeSpan?

this my ForgotPassword method:这是我的忘记密码方法:

public async Task<IActionResult> OnPostAsync()
        {
            if (ModelState.IsValid)
            {
                var user = await _userManager.FindByEmailAsync(Input.Email);
                if (user == null || !(await _userManager.IsEmailConfirmedAsync(user)))
                {
                    return RedirectToPage("./ForgotPasswordConfirmation");
                }
                
                var code = await _userManager.GenerateUserTokenAsync(user, TokenOptions.DefaultPhoneProvider, "ResetPasswordTokenPurpose");//create 6 digit code and use it in send sms
             
                code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
                sendSms(code);                
                return RedirectToPage("./ForgotPasswordConfirmation");
            }

            return Page();
        }

this is ResetPassword method:这是 ResetPassword 方法:

public async Task<IActionResult> OnPostAsync()
        {
            if (!ModelState.IsValid)
            {
                return Page();
            }

            var user = await _userManager.FindByEmailAsync(Input.Email);
            if (user == null)
            {
                // Don't reveal that the user does not exist
                return RedirectToPage("./ResetPasswordConfirmation");
            }

            var tokenVerified = await _userManager.VerifyUserTokenAsync(user, TokenOptions.DefaultPhoneProvider, "ResetPasswordTokenPurpose", Input.Code);//check validate 6 digit code
            if (!tokenVerified)
                return Page();

            var token = await _userManager.GeneratePasswordResetTokenAsync(user);//new token for reseting password

            var result = await _userManager.ResetPasswordAsync(user, token, Input.Password);
            if (result.Succeeded)
            {
                return RedirectToPage("./ResetPasswordConfirmation");
            }

            foreach (var error in result.Errors)
            {
                ModelState.AddModelError(string.Empty, error.Description);
            }
            return Page();
        }

Change the ResetPassword token lifespan:更改 ResetPassword 令牌寿命:

 public class CustomResetPasswordTokenProvider<TUser>
                              : DataProtectorTokenProvider<TUser> where TUser : class
    {
        public CustomResetPasswordTokenProvider(
            IDataProtectionProvider dataProtectionProvider,
            IOptions<ResetPasswordTokenProviderOptions> options)
                                           : base(dataProtectionProvider, options)
        {

        }
    }
    public class ResetPasswordTokenProviderOptions : DataProtectionTokenProviderOptions
    {
        public ResetPasswordTokenProviderOptions()
        {
            Name = "ResetPasswordProtectorTokenProvider";
            TokenLifespan = TimeSpan.FromMinutes(2);
        }
    }

call it in StartUp.cs:在 StartUp.cs 中调用它:

services.AddDefaultIdentity<IdentityUser>(config =>
            {
                config.Tokens.ProviderMap.Add("CustomResetPassword",
                    new TokenProviderDescriptor(
                        typeof(CustomResetPasswordTokenProvider<IdentityUser>)));
                config.Tokens.PasswordResetTokenProvider = "CustomResetPassword";
            }).AddEntityFrameworkStores<ApplicationDbContext>();

            services.AddTransient<CustomResetPasswordTokenProvider<IdentityUser>>();
config.Tokens.PasswordResetTokenProvider = "CustomResetPassword";

In your configuration, you only set your custom provider for the PasswordResetTokenProvider .在您的配置中,您仅为PasswordResetTokenProvider设置自定义提供程序。 So this configuration only applies to the method pair GeneratePasswordResetTokenAsync and ResetPasswordAsync .所以这个配置只适用于方法对GeneratePasswordResetTokenAsyncResetPasswordAsync But you are using these methods only internally to actually perform the password reset using a very short-lived token.但是您仅在内部使用这些方法来使用非常短暂的令牌实际执行密码重置。 So the lifetime limitation here is actually not needed since the token will never leave the application and is used immediately within the same second anyway.所以实际上不需要这里的生命周期限制,因为令牌永远不会离开应用程序并且无论如何都会在同一秒内立即使用。

Instead, what you are doing is use the DefaultPhoneProvider to create the password token that is sent via SMS:相反,您正在做的是使用DefaultPhoneProvider创建通过 SMS 发送的密码令牌:

var code = await _userManager.GenerateUserTokenAsync(user, TokenOptions.DefaultPhoneProvider, "ResetPasswordTokenPurpose");

Now, the default phone provider uses a TOTP-based implementation, time-based one-time passwords .现在,默认电话提供商使用基于 TOTP 的实现,即基于时间的一次性密码 These passwords are by design time-restricted and not valid for an infinite amount of time.这些密码在设计上是有时间限制的,并且在无限时间内无效。 According to spec , the time window, in which a single token is considered valid, is meant to be rather small.根据 spec ,时间 window,其中单个令牌被认为是有效的,意味着相当小。

The implementation that is used by the phone provider uses a fixed time window of 3 minutes, and also accepts two additional time windows in each direction to account for time shifts, resulting in a total theoretical range of 15 minutes in which the user has the chance to retrieve the SMS and enter the code.电话提供商使用的实现使用 3 分钟的固定时间 window,并且还在每个方向上接受两个额外的时间 windows 以解决时移问题,从而使用户有机会的总理论范围为 15 分钟检索短信并输入代码。

If you want to further restrict this, you should first consider that there is no guaranteed SMS delivery time, so choosing a too small window can potentially lock out users if the SMS does not deliver on time or if they are not able to enter it quickly enough.如果你想进一步限制这个,你应该首先考虑没有保证的短信发送时间,所以选择一个太小的 window 可能会在短信没有按时发送或者他们无法快速输入时锁定用户足够的。

If you do want to go that route though, you can provide your own implementation for the TOTP token provider which uses a different window size.如果您确实想要 go 该路由,您可以为TOTP 令牌提供程序提供您自己的实现,它使用不同的 window 大小。 Note that you will have to implement the token generation yourself though since the implementation is internal .请注意,您必须自己实施令牌生成,因为实施是内部的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM