具有自定义身份验证的Web API 2 OAuth承载令牌

时间:2016-06-09 17:47:27

标签: authentication oauth-2.0 asp.net-web-api2

我对C#Web API 2服务有以下要求:

该服务通过电子邮件和发送到其收件箱的临时密码的组合对用户进行身份验证,作为身份验证的一个因素。 我需要将此身份验证机制与生成OAuth承载令牌相结合以保护服务,并使用标准的ASP.NET授权机制通过某种[Authorize]属性检查针对令牌的每个请求。

我已成功实施这些步骤

  1. 用户请求密码
  2. 系统生成并通过电子邮件将密码发送给用户,有效期为30天
  3. 用户通过电子邮件+密码进行身份验证
  4. 系统检查密码的有效性
  5. 但我不知道如何开始实施其余步骤

    1. 如果密码有效,系统会生成OAuth承载令牌
    2. OAuth持票令牌的持续时间与密码到期日期一样长
    3. 使用ASP.NET Identity授权属性执行身份验证和授权检查
    4. 使用OWIN安全和OAuth中间件创建令牌
    5. 使用基于声明的授权并将声明序列化为令牌
    6. 引用的流程仅描述了使用ASP.NET身份个人用户帐户作为验证方式,而不是我想要进行身份验证的方式。

      http://www.asp.net/web-api/overview/security/individual-accounts-in-web-api

      我实际上需要通过检查电子邮件和密码进行身份验证。

2 个答案:

答案 0 :(得分:4)

我曾在类似的情况下工作,并实施了身份验证过滤器(IAuthenticationFilter)和从OAuthAuthorizationServerProvider继承的自定义类。就我而言,我需要使用OAuth和旧令牌对请求进行身份验证。我相信在您的情况下,您需要自定义AuthenticationFilter。请参阅下面的AuthenticationFilter

示例
public class MyAuthenticationFilter : IAuthenticationFilter
{
    private readonly string _authenticationType;

    /// <summary>Initializes a new instance of the <see cref="HostAuthenticationFilter"/> class.</summary>
    /// <param name="authenticationType">The authentication type of the OWIN middleware to use.</param>
    public MyAuthenticationFilter(string authenticationType)
    {
        if (authenticationType == null)
        {
            throw new ArgumentNullException("authenticationType");
        }

        _authenticationType = authenticationType;
    }

    /// <summary>Gets the authentication type of the OWIN middleware to use.</summary>
    public string AuthenticationType
    {
        get { return _authenticationType; }
    }

    /// <inheritdoc />
    public async Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
    {
        if (context == null)
        {
            throw new ArgumentNullException("context");
        }

        HttpRequestMessage request = context.Request;

        if (request == null)
        {
            throw new InvalidOperationException("Request mut not be null");
        }


        //In my case, i need try autenticate the request with BEARER token (Oauth)
        IAuthenticationManager authenticationManager = GetAuthenticationManagerOrThrow(request);

        cancellationToken.ThrowIfCancellationRequested();
        AuthenticateResult result = await authenticationManager.AuthenticateAsync(_authenticationType);
        ClaimsIdentity identity = null;

        if (result != null)
        {
            identity = result.Identity;

            if (identity != null)
            {
                context.Principal = new ClaimsPrincipal(identity);
            }
        }
        else
        {
            //If havent success with oauth authentication, I need locate the legacy token
//If dont exists the legacy token, set error (will generate http 401)
            if (!request.Headers.Contains("legacy-token-header"))
                context.ErrorResult = new AuthenticationFailureResult(Resources.SAUTH_ERROR_LEGACYTOKENNOTFOUND, request);
            else
            {
                try
                {
                    var queryString = request.GetQueryNameValuePairs();
                    if (!queryString.Any(x => x.Key == "l"))
                        context.ErrorResult = new AuthenticationFailureResult(Resources.SAUTH_ERROR_USERTYPENOTFOUND, request);
                    else
                    {
                        var userType = queryString.First(x => x.Key == "l").Value;
                        String token = HttpUtility.UrlDecode(request.Headers.GetValues("tk").First());

                        identity = TokenLegacy.ValidateToken(token, userType);
                        identity.AddClaims(userType, (OwinRequest) ((OwinContext)context.Request.Properties["MS_OwinContext"]).Request);
                        if (identity != null)
                        {
                            context.Principal = new ClaimsPrincipal(identity);
                        }
                    }

                }
                catch (Exception e)
                {
                    context.ErrorResult = new AuthenticationFailureResult(e.Message, request);
                }
            }
        }
    }


    /// <inheritdoc />
    public Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken)
    {
        if (context == null)
        {
            throw new ArgumentNullException("context");
        }

        HttpRequestMessage request = context.Request;

        if (request == null)
        {
            throw new InvalidOperationException("Request mut not be null");
        }

        IAuthenticationManager authenticationManager = GetAuthenticationManagerOrThrow(request);

        // Control the challenges that OWIN middleware adds later.
        authenticationManager.AuthenticationResponseChallenge = AddChallengeAuthenticationType(
            authenticationManager.AuthenticationResponseChallenge, _authenticationType);

        return TaskHelpers.Completed();
    }

    /// <inheritdoc />
    public bool AllowMultiple
    {
        get { return true; }
    }

    private static AuthenticationResponseChallenge AddChallengeAuthenticationType(
        AuthenticationResponseChallenge challenge, string authenticationType)
    {
        Contract.Assert(authenticationType != null);

        List<string> authenticationTypes = new List<string>();
        AuthenticationProperties properties;

        if (challenge != null)
        {
            string[] currentAuthenticationTypes = challenge.AuthenticationTypes;

            if (currentAuthenticationTypes != null)
            {
                authenticationTypes.AddRange(currentAuthenticationTypes);
            }

            properties = challenge.Properties;
        }
        else
        {
            properties = new AuthenticationProperties();
        }

        authenticationTypes.Add(authenticationType);

        return new AuthenticationResponseChallenge(authenticationTypes.ToArray(), properties);
    }

    private static IAuthenticationManager GetAuthenticationManagerOrThrow(HttpRequestMessage request)
    {
        Contract.Assert(request != null);

        var owinCtx = request.GetOwinContext();
        IAuthenticationManager authenticationManager = owinCtx != null ? owinCtx.Authentication : null;

        if (authenticationManager == null)
        {
            throw new InvalidOperationException("IAuthenticationManagerNotAvailable");
        }

        return authenticationManager;
    }
}

WebApiConfig.cs中,您需要添加如下身份验证过滤器:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // Web API configuration and services
        // Configure Web API to use only bearer token authentication.
        config.SuppressDefaultHostAuthentication();

        config.Filters.Add(new MyAuthenticationFilter(OAuthDefaults.AuthenticationType));
     }
}

我建议阅读官方WEB API海报:

https://www.asp.net/media/4071077/aspnet-web-api-poster.pdf

答案 1 :(得分:0)

有关如何在asp.net Web API中设置身份验证的详细说明,请参阅此post。这可以让您了解如何在Web API中实现对您的需求的身份验证。如果您有任何问题或疑问,请与我们联系。

谢谢你, 索玛。