ASP.NET Core & 双因素验证2FA 实战经验分享
必读
本文源码核心逻辑使用AspNetCore.Totp,为什么不使用AspNetCore.Totp而是使用源码封装后面将会说明。
为了防止不提供原网址的转载,特在这里加上原文链接:
https://www.cnblogs.com/yuefengkai/p/11408339.html
双因素认证
双因素身份认证就是通过你所知道再加上你所能拥有的这二个要素组合到一起才能发挥作用的身份认证系统。双因素认证是一种采用时间同步技术的系统,采用了基于时间、事件和密钥三变量而产生的一次性密码来代替传统的静态密码。每个动态密码卡都有一个唯一的密钥,该密钥同时存放在服务器端,每次认证时动态密码卡与服务器分别根据同样的密钥,同样的随机参数(时间、事件)和同样的算法计算了认证的动态密码,从而确保密码的一致性,从而实现了用户的认证。就像我们去银行办卡送的口令牌.

一. 前言
最近公司内部SSO登录一直在找一种安全的方式,目前已实现方案:账号密码登录以及手机验证码登录,通过Apollo切换不同的登录方式,想起18年看到AspNetCore.Totp并也编写了DemodotNetCore-2FA登录,将之前写的再完善并且在此记录和分析,希望对大家有些帮助。
二. AspNetCore.Totp
说明一下为什么要用AspNetCore.Totp修改并且重新打包Brook.Totp因AspNetCore.Totp在生成二维码链接时会访问404(google.com)网站,国内基本无法使用,这很不清真,还有就是注入需要注入接口和实现类,使用起来很繁琐,所以才萌生了让使用起来更方便,并且不依赖Google生成二维码
- 生成二维码
 
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
            };
- 注入方式
Startup注入 
services.AddSingleton<ITotpSetupGenerator, TotpSetupGenerator>();
services.AddSingleton<ITotpValidator, TotpValidator>();
services.AddSingleton<ITotpGenerator, TotpGenerator>();
Controller注入
 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);
        }
三. Brook.Totp
- 二维码使用
QRCoder来生成,不依赖外部网络 
        /// <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}";
        }
- 注入方式
Startup注入 
services.AddBrookTotp();
Controller注入
private readonly ITotp _totp;
public AccountController(ITotp totp)
{
        _totp = totp;
}
四.双因素APP
推荐使用Microsoft Authenticator支持IOS、安卓可自动备份
之前使用Google Authenticator手机坏了 Gitlab和DropBox 再也进不去了(心疼自己三秒钟)
五. 完整流程效果图
使用Microsoft Authenticator

- 正常登录

 - 登录成功后绑定

 - 绑定后再次登录

 
六.如何使用
所有源代码请参照我的GitHub https://github.com/yuefengkai/Brook.Totp
Demo中使用了
EF Core In Memory Database所有的数据只存在内存中Cache in-memorydotNET Core Authentication
下方只展示部分代码
- 新建netCoreMVC项目添加Nuget包
Brook.Totp

 - Startup注入
 
services.AddMemoryCache();
services.AddSingleton<ICacheManage, CacheManage>();
services.AddBrookTotp();
services.AddDbContext<BrookTotpDBContext>(options => options.UseInMemoryDatabase(databaseName: "BrookTotpDB"));
- Controller使用
 
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" });
}
七.写在最后
以上所有源代码已开源在 https://github.com/yuefengkai/Brook.Totp
如果觉得有用请给我个Start!
作者:Brook(高增智)
ASP.NET Core & 双因素验证2FA 实战经验分享的更多相关文章
- 《ASP.NET Core技术内幕与项目实战》精简集-目录
		
本系列是杨中科2022年最新作品<ASP.NET Core技术内幕与项目实战>及B站配套视频(强插点赞)的精简集,是一个读书笔记.总结和提炼了主要知识点,遵守代码优先原则,以利于快速复习和 ...
 - 自动化CodeReview - ASP.NET Core请求参数验证
		
自动化CodeReview系列目录 自动化CodeReview - ASP.NET Core依赖注入 自动化CodeReview - ASP.NET Core请求参数验证 参数验证实现 在做服务端开发 ...
 - 使用JWT的ASP.NET CORE令牌身份验证和授权(无Cookie)——第1部分
		
原文:使用JWT的ASP.NET CORE令牌身份验证和授权(无Cookie)--第1部分 原文链接:https://www.codeproject.com/Articles/5160941/ASP- ...
 - 简读《ASP.NET Core技术内幕与项目实战》之3:配置
		
特别说明:1.本系列内容主要基于杨中科老师的书籍<ASP.NET Core技术内幕与项目实战>及配套的B站视频视频教程,同时会增加极少部分的小知识点2.本系列教程主要目的是提炼知识点,追求 ...
 - 快读《ASP.NET Core技术内幕与项目实战》EFCore2.5:集合查询原理揭秘(IQueryable和IEnumerable)
		
本节内容,涉及4.6(P116-P130).主要NuGet包:如前述章节 一.LINQ和EFCore的集合查询扩展方法的区别 1.LINQ和EFCore中的集合查询扩展方法,虽然命名和使用完全一样,都 ...
 - 快读《ASP.NET Core技术内幕与项目实战》WebApi3.1:WebApi最佳实践
		
本节内容,涉及到6.1-6.6(P155-182),以WebApi说明为主.主要NuGet包:无 一.创建WebApi的最佳实践,综合了RPC和Restful两种风格的特点 1 //定义Person类 ...
 - 第9期Unity User Group Beijing图文报道:《Unity实战经验分享》
		
时间来到了金秋九月,北京UUG活动也来到了第九期.本次活动的主题为<Unity实战经验分享>,为此我们邀请了3位资深的行业大神.这次我们仍然在北京市海淀区丹棱街5号微软大厦举行活动,在这里 ...
 - Visual Studio 2015开发Qt项目实战经验分享(附项目示例源码)
		
Visual Studio 2015开发Qt项目实战经验分享(附项目示例源码) 转 https://blog.csdn.net/lhl1124281072/article/details/800 ...
 - ASP.NET Core 使用Cookie验证身份
		
ASP.NET Core 1.x提供了通过Cookie 中间件将用户主体序列化为一个加密的Cookie,然后在后续请求中验证Cookie并重新创建主体,并将其分配给HttpContext.User属性 ...
 
随机推荐
- 第12组 Alpha冲刺(4/6)
			
Header 队名:To Be Done 组长博客 作业博客 团队项目进行情况 燃尽图(组内共享) 由于这两天在修bug,燃尽图没有下降 展示Git当日代码/文档签入记录(组内共享) 注: 由于Git ...
 - 【AtCoder】 ARC 103
			
link C-//// 直接算会出现奇偶两组选了同一个数,注意处理一下就行 #include<bits/stdc++.h> #define ll long long #define dbg ...
 - MySQL explain使用
			
1.介绍 EXPLAIN 命令用于SQL语句的查询执行计划.这条命令的输出结果能够让我们了解MySQL 优化器(optimlzer)是如何执行SQL 语句的.这条命令并没有提供任何调整建议,但它能够提 ...
 - java.lang.NumberFormatException: Infinite or NaN原因之浮点类型除数为0结果探究
			
背景 在对Double类型的数据进行计算操作,将结果转化为BigDecimal时抛出了下面的异常,进行了Debug才发现了问题原因,同时也暴露出了自己在一些基础知识上还有些欠缺. Exception ...
 - Zookeeper运维常用四字命令
			
Zookeeper运维常用四字命令 echo stat|nc 127.0.0.1 2181 查看哪个节点被选择作为follower或者leader 使用echo ruok|nc 127.0.0.1 2 ...
 - String字符串与其他格式(int、boolean等八大数据类型)的相互转换
			
1.(String 转 int)String str = "123"; int a = Integer.parseInt(str);(int 转 String)int a = 5; ...
 - 使用spring validation完成数据后端校验-自定义校验的注解-判断是否为空
			
引入依赖 我们使用maven构建springboot应用来进行demo演示. <dependencies> <dependency> <groupId>org.sp ...
 - go-micro框架学习1-准备工作
			
下载golang环境,地址:https://studygolang.com/dl,这里使用的是1.11.10版本. 下载golang IDE,这里使用Lite,下载地址:http://liteide. ...
 - disruptor 组件理解
			
disruptor 中核心组件包括 RingBuffer.Event .EventHandler.Sequence.Sequence Barrier. WaitStrategy.WorkProcess ...
 - RFC2119 规范内容
			
RFC2119 https://www.ietf.org/rfc/rfc2119.txt Network Working Group S. Bradner Request for Comments: ...