使用谷歌身份验证器为系统添加动态密码验证
最近公司项目需要用到动态密码登陆,寻找多种解决方案,最后确认使用谷歌身份验证器(Google身份验证器、Google Authenticator) 。
其他备选的方案有国内厂家提供的动态密钥硬件(类似网易将军令)、微软提供的类似谷歌身份验证器的解决方案(找的相关资料不多,如果有谁知道的请留言)
用谷歌身份验证器的原因:
- 客户端为APP,有安卓和IOS , IOS端在App Store 可以搜索下载。
- C#有封装好的相关类可用 (Nuget中搜索 Google Authenticator 即可)
- 客户使用复杂度不高(扫码建立、手动输入建立)
先说逻辑及相关流程,后面贴代码
- 密钥说明:
- 密钥A: 作为密钥种子
- 密钥B:使用密钥种子+使用者账号组成(也可以系统为每个账号生成一个密钥B,而不需要密钥A,但需要每个账号都储存这个密钥B,使用种子+账号的方式可以不用存储)
- 密钥C:使用密钥B 调用谷歌的加密方法,得到APP端可输入的密钥
- 使用说明:
- 在账户管理,或者个人中心,勾选是否登陆使用动态验证码,点击【生成密钥按钮】 调用CreateCode方法,产生密钥C显示,且out 的ImgContent 可以直接放在img的html标签的src属性显示成对应的二维码图片
- 客户使用APP扫描或输入相关的账号和密钥,APP就会开始每30秒自动刷新生成一个6位的动态验证码
- 客户在登陆时,系统使用 当前登录账号 +动态密码 调用ValidateCode 验证是否正确
APP端
第三方DLL引用(Nuget)及版本
核心代码如下:
/// <summary> /// 谷歌身份验证器 /// </summary> public class GoogleAuthor { //加密种子 密钥A private static string baseKey = "qwertyuiopasdfghjkl"; /// <summary> /// 创建密钥 (若修改登陆账号,则相关加密解密需要重新绑定) /// </summary> /// <param name="Account_No">系统用户登陆账号</param> /// <param name="ImgContent">返回img图片内容,包含账号和密钥信息,用户可用app扫描</param> /// <returns>返回用户输入客户端用的密钥字符串</returns> public static string CreateCode(string Account_No, out string ImgContent) { string scKey = baseKey + Account_No.Replace(" ", "");//加密密钥 密钥B ImgContent = ""; Google.Authenticator.TwoFactorAuthenticator tf = new Google.Authenticator.TwoFactorAuthenticator(); //生成客户端需要输入的密钥 密钥C var sc = tf.GenerateSetupCode("System", Account_No.Replace(" ",""), scKey, false, 300); ImgContent = sc.QrCodeSetupImageUrl; //data:image/png;base64 开头的图片字符串。可以直接展示。 //sc.ManualEntryKey 客户端需要输入的密钥 return sc.ManualEntryKey; } /// <summary> /// 验证动态码 /// </summary> /// <param name="Account_No">账号</param> /// <param name="CodeStr">动态码</param> /// <returns>true: 验证正确 false:验证错误</returns> public static bool ValidateCode(string Account_No, string CodeStr ) { Google.Authenticator.TwoFactorAuthenticator tf = new Google.Authenticator.TwoFactorAuthenticator(); string scKey = baseKey + Account_No.Replace(" ", ""); return tf.ValidateTwoFactorPIN(scKey, CodeStr); //不用时间, 自动默认时间偏移正负5 } }