Owin OAuth Web API Authentication-ValidateClientAuthentication 方法未按请求命中

Owin OAuth Web API Authentication-ValidateClientAuthentication method not getting hit on request

我正在尝试在 ASP.Net Web API2 (MVC) 中实现基于 OAuth Owin 令牌的身份验证。当我在我的控制器上应用 [Authorize] 注释时,请求没有命中 ValidateclientAuthentication 并且我收到错误 "Authorization has been denied for this request"。以下是我的代码:

Startup.cs

[assembly: OwinStartup(typeof(EY.DRA.WebAPI.Startup))]
namespace EY.DRA.WebAPI
{
    public class Startup
    {
        public static string PublicClientId { get; private set; }
        public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }
        public void Configuration(IAppBuilder app)
        {
            ConfigureOAuth(app);
            HttpConfiguration httpConfig = new HttpConfiguration();

            //httpConfig.Formatters.Clear();
            //httpConfig.Formatters.Add(new JsonMediaTypeFormatter());
            //httpConfig.Formatters.JsonFormatter.SerializerSettings =
            //new JsonSerializerSettings
            //{
            //    ContractResolver = new CamelCasePropertyNamesContractResolver()
            //};

            //app.UseWebApi(httpConfig);

            WebApiConfig.Register(httpConfig);
            app.UseWebApi(httpConfig);
        }

        public void ConfigureOAuth(IAppBuilder app)
        {
            try
            {
                // Configure the db context and user manager to use a single instance per request
                app.CreatePerOwinContext(OwinAuthDbContext.Create);
                app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);

                // Enable the application to use a cookie to store information for the signed in user
                // and to use a cookie to temporarily store information about a user logging in with a third party login provider
                app.UseCookieAuthentication(new CookieAuthenticationOptions());
                app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);


                // Configure the application for OAuth based flow
                PublicClientId = "self";

                OAuthOptions = new OAuthAuthorizationServerOptions
                {
                    TokenEndpointPath = new PathString("/Token"),
                    Provider = new AuthorizationServerProvider(PublicClientId),
                    //AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
                    AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30),
                    AllowInsecureHttp = true
                };

                //app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions
                //{
                //    TokenEndpointPath = new PathString("/Token"),
                //    Provider = new AuthorizationServerProvider(PublicClientId),
                //    AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30),
                //    AllowInsecureHttp = true,

                //});
                // Enable the application to use bearer tokens to authenticate users
                 app.UseOAuthBearerTokens(OAuthOptions);
            }
            catch(Exception ex)
            {
                throw ex;
            }

        }

        //private static UserManager<IdentityUser> CreateManager(IdentityFactoryOptions<UserManager<IdentityUser>> options, IOwinContext context)
        //{
        //    var userStore = new UserStore<IdentityUser>(context.Get<OwinAuthDbContext>());
        //    var owinManager = new UserManager<IdentityUser>(userStore);
        //    return owinManager;
        //}
    }

AuthorizationServerProvider.cs

 public class AuthorizationServerProvider: OAuthAuthorizationServerProvider
    {
        private readonly string _publicClientId;
        public AuthorizationServerProvider(string publicClientId)
        {
            if (publicClientId == null)
            {
                throw new ArgumentNullException("publicClientId");
            }

            _publicClientId = publicClientId;
        }

        public override Task TokenEndpoint(OAuthTokenEndpointContext context)
        {
            foreach (KeyValuePair<string, string> property in context.Properties.Dictionary)
            {
                context.AdditionalResponseParameters.Add(property.Key, property.Value);
            }

            return Task.FromResult<object>(null);
        }

        public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
        {
            try
            {
                context.Validated();

                return Task.FromResult<object>(null);
            }
            catch (Exception ex)
            {
                throw ex;
            }

        }

        public override Task ValidateClientRedirectUri(OAuthValidateClientRedirectUriContext context)
        {
            if (context.ClientId == _publicClientId)
            {
                Uri expectedRootUri = new Uri(context.Request.Uri, "/");

                if (expectedRootUri.AbsoluteUri == context.RedirectUri)
                {
                    context.Validated();
                }
            }

            return Task.FromResult<object>(null);
        }

        public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
        {
            UserManager<IdentityUser> userManager = context.OwinContext.GetUserManager<UserManager<IdentityUser>>();
            IdentityUser user;
            try
            {
                user = await userManager.FindAsync(context.UserName, context.Password);
            }
            catch
            {
                // Could not retrieve the user due to error.
                context.SetError("server_error");
                context.Rejected();
                return;
            }
            if (user != null)
            {
                ClaimsIdentity identity = await userManager.CreateIdentityAsync(
                                                        user,
                                                        DefaultAuthenticationTypes.ExternalBearer);
                context.Validated(identity);
            }
            else
            {
                context.SetError("invalid_grant", "Invalid UserId or gpn'");
                context.Rejected();
            }
        }


    }

IdentityConfig.cs :这个 class 实现了 ApplicationManager。 AspNetUser 是从 Asp.Net.Identity.EntityFramework 在后端创建的 table 创建的模型 class。

public class ApplicationUserManager : UserManager<AspNetUser>
    {
        public ApplicationUserManager(IUserStore<AspNetUser> store)
            : base(store)
        {
        }

        public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
        {
            var manager = new ApplicationUserManager(new UserStore<AspNetUser>(context.Get<OwinAuthDbContext>()));

            var dataProtectionProvider = options.DataProtectionProvider;
            if (dataProtectionProvider != null)
            {
                manager.UserTokenProvider = new DataProtectorTokenProvider<AspNetUser>(dataProtectionProvider.Create("ASP.NET Identity"));
            }
            return manager;
        }
    }

AspNetUser.cs:

using Microsoft.AspNet.Identity;
    using Microsoft.AspNet.Identity.EntityFramework;
    using System;
    using System.Collections.Generic;
    using System.Security.Claims;
    using System.Threading.Tasks;

    public partial class AspNetUser : IdentityUser
    {
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
        public AspNetUser()
        {
            this.AspNetUserClaims = new HashSet<AspNetUserClaim>();
            this.AspNetUserLogins = new HashSet<AspNetUserLogin>();
            this.AspNetRoles = new HashSet<AspNetRole>();
        }

        public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<AspNetUser> manager, string authenticationType)
        {
            // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
            var userIdentity = await manager.CreateIdentityAsync(this, authenticationType);
            // Add custom user claims here
            return userIdentity;
        }

        public string Id { get; set; }
        public string Email { get; set; }
        public string PasswordHash { get; set; }
        public string SecurityStamp { get; set; }
        public string PhoneNumber { get; set; }
        public bool TwoFactorEnabled { get; set; }
        public Nullable<System.DateTime> LockoutEndDateUtc { get; set; }
        public int AccessFailedCount { get; set; }
        public string UserName { get; set; }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
        public virtual ICollection<AspNetUserClaim> AspNetUserClaims { get; set; }
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
        public virtual ICollection<AspNetUserLogin> AspNetUserLogins { get; set; }
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
        public virtual ICollection<AspNetRole> AspNetRoles { get; set; }
    }

Global.asax.cs:

public class WebApiApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            GlobalConfiguration.Configure(WebApiConfig.Register);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
        }
    }

WebApiConfig.cs:

public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // enable elmah
            config.Services.Add(typeof(IExceptionLogger), new ElmahExceptionLogger());

            // Web API configuration and services
            // Configure Web API to use only bearer token authentication.
            config.SuppressDefaultHostAuthentication();
            config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));

            // Web API routes
            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional },

                // constraint required so this route only matches valid controller names
                constraints: new { controller = GetControllerNames() }
            );                        
        }

        // helper method that returns a string of all api controller names 
        // in this solution, to be used in route constraints above
        private static string GetControllerNames()
        {
            var controllerNames = Assembly.GetCallingAssembly()
                .GetTypes()
                .Where(x =>
                    x.IsSubclassOf(typeof(ApiController)) &&
                    x.FullName.StartsWith(MethodBase.GetCurrentMethod().DeclaringType.Namespace + ".Controllers"))
                .ToList()
                .Select(x => x.Name.Replace("Controller", ""));

            return string.Join("|", controllerNames);
        }
    }
}

我正在应用 [授权] 属性的控制器 class:

[Authorize]
    public class RegisteredUserController : ApiController
    {
        private readonly IRegisteredUserService _regUsrServices;

        #region Constructors

        public RegisteredUserController()
        {
            _regUsrServices = new RegisteredUserService();
        }

        #endregion

        public List<RegisteredUserDTO> GetRegisteredUser()
        {
            return _regUsrServices.GetRegisteredUser();
        }
    }

上面代码的问题是当一个新的请求进来时(例如http://localhost:44720/api/RegisteredUser),执行通过 ConfigureOAuth(IAppBuilder app) -> AppicationUserManager.Create -> 然后直接到 RegisteredUserController,而不去 AuthorizationServerProvider -> ValidateClientAuthentication。 header 已正确传递,我可以从 IOwinContext 上下文中查看它。请帮助我如何点击 ValidateClientAuthentication 方法来验证请求。

以下是我对服务器的请求在 Postman 中的样子:

当我发送 /Token 时,我收到 'unsupported_grant_type' 错误: 在此调用中,ValidateClientAuthentication 受到攻击。请帮忙

Authorization Server的主要目的是在资源拥有者的认可下向第三方客户端颁发token。您可以从 OAuthOptions 中定义的端点获取令牌。 查看此 link 了解更多信息。 http://bitoftech.net/2014/06/01/token-based-authentication-asp-net-web-api-2-owin-asp-net-identity/