最近公司項目需要用到動態密碼登陸,尋找多種解決方案,最后確認使用谷歌身份驗證器(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 } }