1.maf帮助类
public class GoogleAuthenticator
{
private readonly static DateTime _epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
private TimeSpan DefaultClockDriftTolerance { get; set; }
public GoogleAuthenticator()
{
DefaultClockDriftTolerance = TimeSpan.FromSeconds(30);
}
///
/// Generate a setup code for a Google Authenticator user to scan
///
/// Issuer ID (the name of the system, i.e. 'MyApp'), can be omitted but not recommended https://github.com/google/google-authenticator/wiki/Key-Uri-Format
/// Account Title (no spaces)
/// Account Secret Key
/// Number of pixels per QR Module (2 pixels give ~ 100x100px QRCode)
/// SetupCode object
public SetupCode GenerateSetupCode(string issuer, string accountTitleNoSpaces, string accountSecretKey, int QRPixelsPerModule)
{
byte[] key = Encoding.UTF8.GetBytes(accountSecretKey);
return GenerateSetupCode(issuer, accountTitleNoSpaces, key, QRPixelsPerModule);
}
///
/// Generate a setup code for a Google Authenticator user to scan
///
/// Issuer ID (the name of the system, i.e. 'MyApp'), can be omitted but not recommended https://github.com/google/google-authenticator/wiki/Key-Uri-Format
/// Account Title (no spaces)
/// Account Secret Key as byte[]
/// Number of pixels per QR Module (2 = ~120x120px QRCode)
/// SetupCode object
public SetupCode GenerateSetupCode(string issuer, string accountTitleNoSpaces, byte[] accountSecretKey, int QRPixelsPerModule)
{
if (accountTitleNoSpaces == null) { throw new NullReferenceException("Account Title is null"); }
accountTitleNoSpaces = RemoveWhitespace(accountTitleNoSpaces);
string encodedSecretKey = Base32Encoding.ToString(accountSecretKey);
string provisionUrl = null;
provisionUrl = String.Format("otpauth://totp/{2}:{0}?secret={1}&issuer={2}", accountTitleNoSpaces, encodedSecretKey.Replace("=", ""), UrlEncode(issuer));
using (QRCodeGenerator qrGenerator = new QRCodeGenerator())
using (QRCodeData qrCodeData = qrGenerator.CreateQrCode(provisionUrl, QRCodeGenerator.ECCLevel.M))
using (QRCode qrCode = new QRCode(qrCodeData))
using (Bitmap qrCodeImage = qrCode.GetGraphic(QRPixelsPerModule))
using (MemoryStream ms = new MemoryStream())
{
qrCodeImage.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
return new SetupCode(accountTitleNoSpaces, encodedSecretKey, String.Format("data:image/png;base64,{0}", Convert.ToBase64String(ms.ToArray())));
}
}
private static string RemoveWhitespace(string str)
{
return new string(str.Where(c => !Char.IsWhiteSpace(c)).ToArray());
}
private string UrlEncode(string value)
{
StringBuilder result = new StringBuilder();
string validChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~";
foreach (char symbol in value)
{
if (validChars.IndexOf(symbol) != -1)
{
result.Append(symbol);
}
else
{
result.Append('%' + String.Format("{0:X2}", (int)symbol));
}
}
return result.ToString().Replace(" ", "%20");
}
public string GeneratePINAtInterval(string accountSecretKey, long counter, int digits = 6)
{
return GenerateHashedCode(accountSecretKey, counter, digits);
}
internal string GenerateHashedCode(string secret, long iterationNumber, int digits = 6)
{
byte[] key = Encoding.UTF8.GetBytes(secret);
return GenerateHashedCode(key, iterationNumber, digits);
}
internal string GenerateHashedCode(byte[] key, long iterationNumber, int digits = 6)
{
byte[] counter = BitConverter.GetBytes(iterationNumber);
if (BitConverter.IsLittleEndian)
{
Array.Reverse(counter);
}
HMACSHA1 hmac = new HMACSHA1(key);
byte[] hash = hmac.ComputeHash(counter);
int offset = hash[hash.Length - 1] & 0xf;
// Convert the 4 bytes into an integer, ignoring the sign.
int binary =
((hash[offset] & 0x7f) << 24)
| (hash[offset + 1] << 16)
| (hash[offset + 2] << 8)
| (hash[offset + 3]);
int password = binary % (int)Math.Pow(10, digits);
return password.ToString(new string('0', digits));
}
private long GetCurrentCounter()
{
return GetCurrentCounter(DateTime.UtcNow, _epoch, 30);
}
private long GetCurrentCounter(DateTime now, DateTime epoch, int timeStep)
{
return (long)(now - epoch).TotalSeconds / timeStep;
}
public bool ValidateTwoFactorPIN(string accountSecretKey, string twoFactorCodeFromClient)
{
return ValidateTwoFactorPIN(accountSecretKey, twoFactorCodeFromClient, DefaultClockDriftTolerance);
}
public bool ValidateTwoFactorPIN(string accountSecretKey, string twoFactorCodeFromClient, TimeSpan timeTolerance)
{
var codes = GetCurrentPINs(accountSecretKey, timeTolerance);
return codes.Any(c => c == twoFactorCodeFromClient);
}
public string[] GetCurrentPINs(string accountSecretKey, TimeSpan timeTolerance)
{
List codes = new List();
long iterationCounter = GetCurrentCounter();
int iterationOffset = 0;
if (timeTolerance.TotalSeconds > 30)
{
iterationOffset = Convert.ToInt32(timeTolerance.TotalSeconds / 30.00);
}
long iterationStart = iterationCounter - iterationOffset;
long iterationEnd = iterationCounter + iterationOffset;
for (long counter = iterationStart; counter <= iterationEnd; counter++)
{
codes.Add(GeneratePINAtInterval(accountSecretKey, counter));
}
return codes.ToArray();
}
}
2.nugget安装GoogleAuthenticator;
3.
开启mfa时候请求以下接口
public async Task> GoogleImg()
{
try
{
Dictionary dic = new Dictionary();
var UserId = HttpContext.Session.GetString("UserId");
if (UserId != "")
{
var userinfo = _userAirware.Query(u => u.UserId == Convert.ToInt32(UserId)).Result.FirstOrDefault();
if (userinfo != null)
{
if (userinfo.IsSuccess == 0)
{
GoogleAuthenticator tfa = new GoogleAuthenticator();
var guid = Guid.NewGuid().ToString();
SetupCode setupInfo = tfa.GenerateSetupCode("FS Airware", userinfo.UserEmail, guid, 3);
//更新guid到当前登录用户
userinfo.GoogleAuthkey = guid;
await ???.Update(userinfo);
QRImageUrl = setupInfo.QrCodeSetupImageUrl;
ManualEntryKey = setupInfo.ManualEntryKey;
//dic.Add("isverify", "true");
dic.Add("img", QRImageUrl);
return ApiResultHelper.renderSuccess(dic, "Login succeeded");
}
return ApiResultHelper.renderError("ENABLED");
}
}
return ApiResultHelper.renderError("非法请求!");
}
catch (Exception e)
{
return ApiResultHelper.renderError();
}
}
4.验证接口
public async Task> GoogleVerify(string checkcode)
{
var UserId = HttpContext.Session.GetString("UserId");
Dictionary dic1 = new Dictionary();
//判断当前用户是否登录成功
if (UserId != "")
{
var userinfo = _userAirware.Query(u => u.UserId == Convert.ToInt32(UserId)).Result.FirstOrDefault();
if (userinfo != null)
{
if (userinfo.IsVerify == 0)
{
GoogleAuthenticator gat = new GoogleAuthenticator();
var result = gat.ValidateTwoFactorPIN(userinfo.GoogleAuthkey, checkcode);
if (result)
{
Dictionary clims = new Dictionary
{
{"ProjectName",userinfo.UserFirstName }
};
await ???.Update(userinfo);
string token = _jwt.GetToken(clims);
dic1.Add("isverify", "true");
dic1.Add("token", token);
dic1.Add("userid", userinfo.UserId + "");
dic1.Add("name", userinfo.UserFirstName);
return ApiResultHelper.renderSuccess(dic1);
}
else
{
return ApiResultHelper.renderError(false);
}
}
}
}
return ApiResultHelper.renderError("非法访问!");
}