ASP.NET Core & 2FA two-factor authentication to share practical experience

Privacy Policy

Core logic source used herein AspNetCore.Totp , why not use AspNetCore.Totpbut the use of the package will be described later source.

To prevent reprint does not provide the original URL, add special text link here:
https://www.cnblogs.com/yuefengkai/p/11408339.html

Two-factor authentication

Two-factor authentication is through you know these two factors plus you can have grouped together to play a role in the authentication system. The use of two-factor authentication is a time synchronization technology system that uses a time-based one-time password, key events and three-variable generated to replace the traditional static passwords. Each dynamic password card has a unique key that is stored on the server at the same time, the dynamic password card every time the server according to the same key, respectively, the same random parameters (time, event), and the same authentication algorithm calculates a dynamic password authentication, ensuring consistency password, enabling user authentication. As we go to the bank to do card to send the password card.

I. Introduction

Recent internal SSO login has been looking for a safe way, the current program has been implemented: the account password and phone verification code by Apollo switch to a different login, remembered 18 years to see AspNetCore.Totp and also prepared a Demo dotNetCore -2FA login, before you write will sound again and this recording and analysis, we want some help.

Two. AspNetCore.Totp

Explain why use AspNetCore.Totpmodified and repackaged Brook.Totpresult AspNetCore.Totpin the generation of two-dimensional code links to access 404 (google.com) website, the country simply can not use, this is not Muslim , there is a need to inject injecting interface and implementation class, using up very tedious, so make it easier for the initiation of use, and does not rely on Google to generate two-dimensional code

  1. Generate two-dimensional code
accountIdentity = accountIdentity.Replace(" ", "");
            var encodedSecretKey = Base32.Encode(accountSecretKey);
            var provisionUrl = UrlEncoder.Encode(string.Format("otpauth://totp/{0}?secret={1}&issuer={2}", accountIdentity, encodedSecretKey, UrlEncoder.Encode(issuer)));
            var protocol = useHttps ? "https" : "http";
            var url = $"{protocol}://chart.googleapis.com/chart?cht=qr&chs={qrCodeWidth}x{qrCodeHeight}&chl={provisionUrl}";
            var totpSetup = new TotpSetup
            {
                QrCodeImage = this.GetQrImage(url),
                ManualSetupKey = encodedSecretKey
            };
  1. Injection method
    Startup injection
services.AddSingleton<ITotpSetupGenerator, TotpSetupGenerator>();
services.AddSingleton<ITotpValidator, TotpValidator>();
services.AddSingleton<ITotpGenerator, TotpGenerator>();

Controller injection

 private readonly ITotpGenerator _totpGenerator;
        private readonly ITotpSetupGenerator _totpSetupGenerator;
        private readonly ITotpValidator _totpValidator;


        public ValuesController(ITotpSetupGenerator totpSetupGenerator)
        {
            _totpSetupGenerator = totpSetupGenerator;
            _totpGenerator = new TotpGenerator();
            _totpValidator = new TotpValidator(_totpGenerator);
        }

Three. Brook.Totp

  1. A two-dimensional code used QRCoderto generate the two-dimensional code, does not rely on external network
        /// <summary>
        /// 生成二维码
        /// </summary>
        /// <param name="provisionUrl"></param>
        /// <param name="pixelsPerModule"></param>
        /// <returns></returns>
        private string GetQrBase64Imageg(string provisionUrl,int pixelsPerModule)
        {
            QRCodeGenerator qrGenerator = new QRCodeGenerator();
            QRCodeData qrCodeData = qrGenerator.CreateQrCode(provisionUrl, QRCodeGenerator.ECCLevel.Q);
            Base64QRCode qrCode = new Base64QRCode(qrCodeData);
            string qrCodeImageAsBase64 = qrCode.GetGraphic(2);

            return  $"data:image/png;base64,{qrCodeImageAsBase64}";
        }
  1. Injection method
    Startup injection
services.AddBrookTotp();

Controller injection

private readonly ITotp _totp;
public AccountController(ITotp totp)
{
        _totp = totp;
}

IV. Two-factor APP

Recommended use Microsoft Authenticator support IOS, Android can automatically backup
before using Google Authenticator phone is broken Gitlab and DropBox can no longer get in (distressed that their three seconds)

V. complete process renderings

Use Microsoft Authenticator

  1. Normal login
  2. After a successful login Bind
  3. Log in again after binding

VI. How to use

All the source code, please refer to my GitHub https://github.com/yuefengkai/Brook.Totp
Demo in use

  1. EF Core In Memory DatabaseAll data exists only in memory
  2. Cache in-memory
  3. dotNET Core Authentication

Below only shows part of the code

  1. New items are added Nuget package netCoreMVCBrook.Totp
  2. Startup injection
services.AddMemoryCache();
services.AddSingleton<ICacheManage, CacheManage>();
services.AddBrookTotp();
services.AddDbContext<BrookTotpDBContext>(options => options.UseInMemoryDatabase(databaseName: "BrookTotpDB"));
  1. Controller uses
private readonly ITotp _totp;
public AccountController(ITotp totp)
{
        _totp = totp;
}
//获取二维码
[Authorize]
public IActionResult GetQr()
{
    var totpSetup = _totp.GenerateUrl("dotNETBuild", CurremtUser.Email, CurremtUser.SecretKeyFor2FA);

    return Json(new { qrCodeContennt = totpSetup.QrCodeImageContent });
}
//验证双因素校验码
[Authorize]
[HttpPost]
public async Task<IActionResult> Valid(int code)
{
    var valid = _totp.Validate(CurremtUser.SecretKeyFor2FA
        , code, 30);

    if (!valid)
    {
        return Json(new { result = 0, msg = "2FA校验失败" });
    }
    //校验成功后 如果是第一次绑定校验 需将用户的accountSecretKey 存入数据库
    CurremtUser.IsOpen2FA = true;

    await _userService.UpdateAsync(CurremtUser);

    _cacheManage.Remove(string.Format(CacheKeys.GetUserForEmail, CurremtUser.Email));

    var claims = new List<Claim>
    {
        new Claim("user", CurremtUser.Email),
        new Claim("role", "Member")
    };

    await HttpContext.SignInAsync(new ClaimsPrincipal(new ClaimsIdentity(claims, "Cookies", "user", "role")));
    return Json(new { result = 1, msg = "2FA校验成功", url = "/Home/Index" });
}

VII. Written in the last

All of the above source code has been open sourced https://github.com/yuefengkai/Brook.Totp
If you find it useful, please give me a Start!

Author: Brook (high Zengzhi)

Guess you like

Origin www.cnblogs.com/yuefengkai/p/11408339.html