身份验证 – 如何使用ASP.NET身份在Web API 2中实现双因素身份验证?

我已经看到了关于如何在web api中创建双因素身份验证的链接 Two Factor Auth using goolgle authenticator,但我的要求却略有不同.

>我想使用双因素身份验证来发出访问令牌. (如果用户已选择启用双因素身份验证)
>我想使用ASP.NET身份本身创建OTP代码. (就像我们在MVC Web应用程序中所做的那样SignInManager.SendTwoFactorCodeAsync(“电话代码”))

我当前实现的问题是,当我调用SignInManager.SendTwoFactorCodeAsync(“电话代码”)时,我得到错误用户ID未找到.

为了调试,我尝试调用User.Identity.GetUserId();并返回正确的用户ID.

我检查了Microsoft.AspNet.Identity.Owin程序集的源代码

public virtual async Task<bool> SendTwoFactorCodeAsync(string provider)
    {
        var userId = await GetVerifiedUserIdAsync().WithCurrentCulture();
        if (userId == null)
        {
            return false;
        }

        var token = await UserManager.GenerateTwoFactorTokenAsync(userId,provider).WithCurrentCulture();
        // See IdentityConfig.cs to plug in Email/SMS services to actually send the code
        await UserManager.NotifyTwoFactorTokenAsync(userId,provider,token).WithCurrentCulture();
        return true;
    }

    public async Task<TKey> GetVerifiedUserIdAsync()
    {
        var result = await AuthenticationManager.AuthenticateAsync(DefaultAuthenticationTypes.TwoFactorCookie).WithCurrentCulture();
        if (result != null && result.Identity != null && !String.IsNullOrEmpty(result.Identity.GetUserId()))
        {
            return ConvertIdFromString(result.Identity.GetUserId());
        }
        return default(TKey);
    }

从上面的代码可以看出,SendTwoFactorCodeAsync方法在内部调用GetVerifiedUserIdAsync,它检查双因素身份验证cookie.由于这是一个web api项目,因此不存在cookie并返回0,导致找不到用户id错误.

我的问题,如何使用asp.net身份在web api中正确实现双因素身份验证?

解决方法

这就是我实现的,以便在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替换参数,如下所示:

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,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(),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
        }
    }

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


这篇文章主要讲解了“WPF如何实现带筛选功能的DataGrid”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“WPF...
本篇内容介绍了“基于WPF如何实现3D画廊动画效果”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这...
Some samples are below for ASP.Net web form controls:(from http://www.visualize.uk.com/resources/asp
问题描述: 对于未定义为 System.String 的列,唯一有效的值是(引发异常)。 For columns not defined as System.String, the only vali
最近用到了CalendarExtender,结果不知道为什么发生了错位,如图在Google和百度上找了很久,中文的文章里面似乎只提到了如何本地化(就是显示中文的月份)以及怎么解决被下拉框挡住的问题,谈
ASP.NET 2.0 page lifecyle ASP.NET 2.0 event sequence changed a lot since 1.1. Here is the order: App
静态声明: &#39; Style=&quot;position: relative&quot; AppendDataBoundItems=&quot;True&quot;&gt; (无 或 空 或
以下内容是从网络上搜集资料,然后整理而来的。不当之处,请不吝指教。(The following were from network, and edited by myself. Thanks in a
Imports System Imports System.Reflection Namespace DotNetNuke &#39;*********************************
Ok so you have all seen them: “8 million tools for web development”, “5 gagillion tools that if you
以下内容来源于: http://blog.csdn.net/cuike519/archive/2005/09/27/490316.aspx 问:为什么Session在有些机器上偶尔会丢失? 答:可能和
以下文章提到可以用“http://localhost/MyWebApp/WebAdmin.axd”管理站点: ---------------------------------------------
Visual Studio 2005 IDE相关的11个提高开发效率的技巧 英文原创来源于: http://www.chinhdo.com/chinh/blog/20070920/top-11-vis
C#日期格式化 from: http://51xingfu.blog.51cto.com/219185/46222 日期转化一 为了达到不同的显示效果有时,我们需要对时间进行转化,默认格式为:2007
from: http://www.nikhilk.net/UpdateControls.aspx Two controls that go along with the UpdatePanel and
Open the report in the Designer. In the ToolBox, select/expand the &quot;Report Items&quot; section.
from: http://drupal.org/node/75844 Do this: find which TinyMCE theme you are using. For the sake of
asp.net中给用户控件添加自定义事件 用户控件中定义好代理和事件: public delegate void ItemSavedDelegate(object sender, EventArgs
在Windows版本的Safari中浏览以下的页面。 http://www.asp.net/AJAX/Control-Toolkit/Live/Calendar/Calendar.aspx Calen
http://aspnet.4guysfromrolla.com/articles/021506-1.aspx By Scott Mitchell Introduction When creating