Owin OAuth Web API身份验证 - ValidateClientAuthentication方法未按请求命中

时间:2018-03-27 04:09:28

标签: c# asp.net-mvc oauth asp.net-web-api2 owin

我正在尝试在ASP.Net Web API2(MVC)中实现基于OAuth Owin令牌的身份验证。当我在我的控制器上应用[授权]注释时,请求没有按下ValidateclientAuthentication,我收到错误"此请求已拒绝授权"。以下是我的代码:

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:此类实现ApplicationManager。 AspNetUser是从Asp.Net.Identity.EntityFramework在后端创建的表创建的模型类。

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);
        }
    }
}

我正在应用[Authorize]属性的控制器类:

[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应用程序) - &gt; AppicationUserManager.Create - &gt;然后它直接进入RegisteredUserController而不去AuthorizationServerProvider - &gt; ValidateClientAuthentication。 标头正确传递,我可以从IOwinContext上下文中查看它。请帮助我如何点击ValidateClientAuthentication方法来验证请求。

以下是我在Postman中对服务器的请求: enter image description here

当我发送/令牌时,我得到了'unsupported_grant_type&#39;错误: enter image description here 在此次调用中,ValidateClientAuthentication受到了攻击。请帮忙。

1 个答案:

答案 0 :(得分:2)

授权服务器的主要目的是在资源所有者的批准下向第三方客户端颁发令牌。您可以从OAuthOptions中定义的端点获取令牌。 请查看此链接以获取更多信息。 http://bitoftech.net/2014/06/01/token-based-authentication-asp-net-web-api-2-owin-asp-net-identity/