簡體   English   中英

如何為 asp.net 核心中 GenerateUserTokenAsync 創建的令牌設置 TimeSpan?

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

我的項目中有“忘記密碼”頁面。 在此頁面上,我使用_userManager.GenerateUserTokenAsync(user, TokenOptions.DefaultPhoneProvider, "ResetPasswordTokenPurpose");創建了 6 位數字然后將此代碼發送給用戶。 現在我想為這段代碼設置 2 分鍾后過期的時間跨度。 我向服務容器添加了一個自定義提供程序,但它不適用於由GenerateUserTokenAsync創建的代碼。而且我不想設置適用於所有令牌的 timeSpan。 如何為此設置自定義 timeSpan?

這是我的忘記密碼方法:

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();
        }

這是 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();
        }

更改 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);
        }
    }

在 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";

在您的配置中,您僅為PasswordResetTokenProvider設置自定義提供程序。 所以這個配置只適用於方法對GeneratePasswordResetTokenAsyncResetPasswordAsync 但是您僅在內部使用這些方法來使用非常短暫的令牌實際執行密碼重置。 所以實際上不需要這里的生命周期限制,因為令牌永遠不會離開應用程序並且無論如何都會在同一秒內立即使用。

相反,您正在做的是使用DefaultPhoneProvider創建通過 SMS 發送的密碼令牌:

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

現在,默認電話提供商使用基於 TOTP 的實現,即基於時間的一次性密碼 這些密碼在設計上是有時間限制的,並且在無限時間內無效。 根據 spec ,時間 window,其中單個令牌被認為是有效的,意味着相當小。

電話提供商使用的實現使用 3 分鍾的固定時間 window,並且還在每個方向上接受兩個額外的時間 windows 以解決時移問題,從而使用戶有機會的總理論范圍為 15 分鍾檢索短信並輸入代碼。

如果你想進一步限制這個,你應該首先考慮沒有保證的短信發送時間,所以選擇一個太小的 window 可能會在短信沒有按時發送或者他們無法快速輸入時鎖定用戶足夠的。

如果您確實想要 go 該路由,您可以為TOTP 令牌提供程序提供您自己的實現,它使用不同的 window 大小。 請注意,您必須自己實施令牌生成,因為實施是內部的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM