這就是我已經實現了這個工作的api。我假設你正在使用默認的ASP.NET單用戶模板。
1 ApplicationOAuthProvider
內GrantResourceOwnerCredentials方法,你必須添加此代碼
var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
ApplicationUser user = await userManager.FindAsync(context.UserName, context.Password);
var twoFactorEnabled = await userManager.GetTwoFactorEnabledAsync(user.Id);
if (twoFactorEnabled)
{
var code = await userManager.GenerateTwoFactorTokenAsync(user.Id, "PhoneCode");
IdentityResult notificationResult = await userManager.NotifyTwoFactorTokenAsync(user.Id, "PhoneCode", code);
if(!notificationResult.Succeeded){
//you can add your own validation here
context.SetError(error, "Failed to send OTP");
}
}
// commented for clarification
ClaimIdentity oAuthIdentity .....
// Commented for clarification
AuthenticationProperties properties = CreateProperties(user);
// Commented for clarification
內CreateProperties法userObject更換paramenter這樣的:
public static AuthenticationProperties CreateProperties(ApplicationUser user)
{
IDictionary<string, string> data = new Dictionary<string, string>
{
{ "userId", user.Id },
{ "requireOTP" , user.TwoFactorEnabled.ToString() },
}
// commented for clarification
}
上面的代碼用於檢查用戶是否啓用了TFA,如果啓用了它,它將生成驗證代碼並使用您選擇的SMSService發送它。
2.創建TwoFactorAuthorize屬性
創建響應類ResponseData
public class ResponseData
{
public int Code { get; set; }
public string Message { get; set; }
}
添加TwoFactorAuthorizeAttribute
public override async Task OnAuthorizationAsync(HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken)
{
#region Get userManager
var userManager = HttpContext.Current.GetOwinContext().Get<ApplicationUserManager>();
if(userManager == null)
{
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized, new ResponseData
{
Code = 100,
Message = "Failed to authenticate user."
});
return;
}
#endregion
var principal = actionContext.RequestContext.Principal as ClaimsPrincipal;
#region Get current user
var user = await userManager.FindByNameAsync(principal?.Identity?.Name);
if(user == null)
{
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized, new ResponseData
{
Code = 100,
Message = "Failed to authenticate user."
});
return;
}
#endregion
#region Validate Two-Factor Authentication
if (user.TwoFactorEnabled)
{
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized, new ResponseData
{
Code = 101,
Message = "User must be authenticated using Two-Factor Authentication."
});
}
#endregion
return;
}
}
3。使用TwoFactorAuthorizeAttribute
在控制器使用TwoFactorAuthorizeAttribute
[Authorize]
[TwoFactorAuthorize]
public IHttpActionResult DoMagic(){
}
4.驗證OTP 在你的AccountController必須添加API端點驗證OTP
[Authorize]
[HttpGet]
[Route("VerifyPhoneOTP/{code}")]
public async Task<IHttpActionResult> VerifyPhoneOTP(string code)
{
try
{
bool verified = await UserManager.VerifyTwoFactorTokenAsync(User.Identity.GetUserId(), "PhoneCode", code);
if (!verified)
return BadRequest($"{code} is not a valid OTP, please verify and try again.");
var result = await UserManager.SetTwoFactorEnabledAsync(User.Identity.GetUserId(), false);
if (!result.Succeeded)
{
foreach (string error in result.Errors)
errors.Add(error);
return BadRequest(errors[0]);
}
return Ok("OTP verified successfully.");
}
catch (Exception exception)
{
// Log error here
}
}
Spharah嗨,非常感謝您的詳細解答。您是否也可以包含用於驗證用戶輸入的OTP代碼的邏輯? –
嗨阿南德,我更新了答案,包括代碼來驗證OTP,不要忘記給予好評的答案:-) – Spharah
Spharah,我已經投了。在接受答案之前,你可以通過疑問來澄清。成功的OTP驗證後,您將IsTwoFactorEnabled設置爲false。假設用戶在另一臺機器上再次登錄,現在他不會得到OTP(正確?),因爲IsTwoFactorEnabled設置爲false。你什麼時候重新啓用它? –