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属性 ...
随机推荐
- @submit.native.prevent作用
<el-form :inline="true" :model="geCarManageData" class="demo-form-inline ...
- 2019 SDN第五次上机作业
2019 SDN第五次上机作业 作业链接 1.浏览RYU官网学习RYU控制器的安装和RYU开发入门教程,提交对于教程代 码的理解,包括但不限于: 安装RYU控制器并测试 安装教程 安装过程及遇到各种问 ...
- [RoarCTF 2019]Online Proxy
目录 [RoarCTF 2019]Online Proxy [RoarCTF 2019]Online Proxy 题目复现链接:https://buuoj.cn/challenges 参考链接:官方w ...
- vue-cli 3.0脚手架搭建项目
1.安装vue-cli 3.0 npm install -g @vue/cli # or yarn global add @vue/cli 安装成功后查看版本:vue -v 2.命令变化 vue cr ...
- CentOS 7 安装 MySql8.0
1-配置 Yum 库 rpm -Uvh https://repo.mysql.com/mysql80-community-release-el7-3.noarch.rpm 2-安装 MySql 2.1 ...
- EF 调试跟踪生成的SQL语句
IQueryable query = from x in appEntities select x; var sql = ((System.Data.Objects.ObjectQuery)query ...
- mysql性能测试-------重要!!!
我们在做性能测试的目的是什么,就是要测出一个系统的瓶颈在哪里,到底是哪里影响了我们系统的性能,找到问题,然后解决它.当然一个系统由很多东西一起组合到一起,应用程序.数据库.服务器.中中间件等等很多东西 ...
- c# 通过json.net中的JsonConverter进行自定义序列化与反序列化
https://www.cnblogs.com/yijiayi/p/10051284.html 相信大家在工作中会经常遇见对json进行序列化与反序列化吧,但通常的序列化与反序列化中的json结构与c ...
- N以内的素数计算(Java代码)
列出小于N的所有素数 普通计算方式, 校验每个数字 优化的几处: 判断是否整除时, 除数使用小于自身的平方根的素数 大于3的素数, 都在6的整数倍两侧, 即 6m - 1 和 6m + 1 publi ...
- ubantu使用ssh服务
Secure Shell(SSH)是一种加密网络协议,用于在不安全的网络上安全地运行网络服务.利用SSH可以实现加密并安全地远程登录计算机系统. Ubuntu安装后默认只有ssh客户端,即只能在Ubu ...