C# 有没有一种方法可以松散地耦合这个基本的身份验证过滤器

C# 有没有一种方法可以松散地耦合这个基本的身份验证过滤器,c#,asp.net-web-api,dependency-injection,ninject,C#,Asp.net Web Api,Dependency Injection,Ninject,我有一个asp.net web api,我想使用基本身份验证。有没有什么方法可以使它松散耦合?我尝试了构造函数DI,但我不知道如何将Dbcontext传递到WebApiConfig。任何帮助都将不胜感激 这是我的界面: public interface IUserValidate { bool Login(string username, string password); } 这是我的班级: public class UserValidate : IUserV

我有一个asp.net web api,我想使用基本身份验证。有没有什么方法可以使它松散耦合?我尝试了构造函数DI,但我不知道如何将Dbcontext传递到WebApiConfig。任何帮助都将不胜感激

这是我的界面:

public interface IUserValidate
    {
        bool Login(string username, string password);
    }
这是我的班级:

public class UserValidate : IUserValidate
    {

        //This method is used to check the user credentials
        public bool Login(string username, string password)
        {
            using (var context = new EPINMiddleWareAPIContext())
            {
                return context.Companies.Any(user =>
                    user.userName.Equals(username, StringComparison.OrdinalIgnoreCase)
                    && user.password == password);
            }

        }
    }
以下是我的基本身份验证筛选器:

public class BasicAuthenticationAttribute : AuthorizationFilterAttribute
    {

        private const string Realm = "My Realm";


        public override void OnAuthorization(HttpActionContext actionContext)
        {
            //If the Authorization header is empty or null
            //then return Unauthorized
            if (actionContext.Request.Headers.Authorization == null)
            {
                actionContext.Response = actionContext.Request
                    .CreateResponse(HttpStatusCode.Unauthorized);
                // If the request was unauthorized, add the WWW-Authenticate header 
                // to the response which indicates that it require basic authentication
                if (actionContext.Response.StatusCode == HttpStatusCode.Unauthorized)
                {
                    actionContext.Response.Headers.Add("WWW-Authenticate",
                        string.Format("Basic realm=\"{0}\"", Realm));
                }
            }
            else
            {
                //Get the authentication token from the request header
                string authenticationToken = actionContext.Request.Headers
                    .Authorization.Parameter;
                //Decode the string
                string decodedAuthenticationToken = Encoding.UTF8.GetString(
                    Convert.FromBase64String(authenticationToken));
                //Convert the string into an string array
                string[] usernamePasswordArray = decodedAuthenticationToken.Split(':');
                //First element of the array is the username
                string username = usernamePasswordArray[0];
                //Second element of the array is the password
                string password = usernamePasswordArray[1];
                //call the login method to check the username and password
                UserValidate uv = new UserValidate();
                if (uv.Login(username, password))
                {
                    var identity = new GenericIdentity(username);
                    IPrincipal principal = new GenericPrincipal(identity, null);
                    Thread.CurrentPrincipal = principal;
                    if (HttpContext.Current != null)
                    {
                        HttpContext.Current.User = principal;
                    }
                }
                else
                {
                    actionContext.Response = actionContext.Request
                        .CreateResponse(HttpStatusCode.Unauthorized);
                }
            }
        }

    }
这是我的网站配置:

public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API configuration and services
            config.Filters.Add(new BasicAuthenticationAttribute());
            // Web API routes
            config.MapHttpAttributeRoutes();
            //Registering GlobalExceptionHandler
            config.Services.Replace(typeof(IExceptionHandler), new GlobalExceptionHandler());
            //Registering UnhandledExceptionLogger
            config.Services.Replace(typeof(IExceptionLogger), new UnhandledExceptionLogger());
            //Registering RequestResponseHandler
            config.MessageHandlers.Add(new RequestResponseHandler());
            //Validate Token
            //config.MessageHandlers.Add(new TokenValidationHandler());

            //Registering CustomExceptionFilter
            config.Filters.Add(new CustomExceptionFilter());

        }
    }
以下是我的Dbcontext:

public class EPINMiddleWareAPIContext : DbContext
    {

        public EPINMiddleWareAPIContext() : base("name=EPINMiddleWareAPIContext")
        {
        }

        public DbSet<InitiateRequest> InitiateRequests { get; set; }
        public DbSet<InitiateResponse> InitiateResponses { get; set; }
        public DbSet<Company> Companies { get; set; }
        public DbSet<ConfirmRequest> ConfirmRequests { get; set; }
        public DbSet<ConfirmResponse> ConfirmResponses { get; set; }
        public DbSet<GameBank> GameBanks { get; set; }
        public DbSet<GameCouponBank> GameCouponBanks { get; set; }

    }
以下是我的Ninject Web Common:

using EPINMiddleWareAPI.Controllers;

[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(EPINMiddleWareAPI.App_Start.NinjectWebCommon), "Start")]
[assembly: WebActivatorEx.ApplicationShutdownMethodAttribute(typeof(EPINMiddleWareAPI.App_Start.NinjectWebCommon), "Stop")]

namespace EPINMiddleWareAPI.App_Start
{
    using System;
    using System.Web;

    using Microsoft.Web.Infrastructure.DynamicModuleHelper;

    using Ninject;
    using Ninject.Web.Common;
    using Models;
    using Ninject.Web.Common.WebHost;

    public static class NinjectWebCommon 
    {
        private static readonly Bootstrapper bootstrapper = new Bootstrapper();

        /// <summary>
        /// Starts the application
        /// </summary>
        public static void Start() 
        {
            DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
            DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
            bootstrapper.Initialize(CreateKernel);
        }

        /// <summary>
        /// Stops the application.
        /// </summary>
        public static void Stop()
        {
            bootstrapper.ShutDown();
        }

        /// <summary>
        /// Creates the kernel that will manage your application.
        /// </summary>
        /// <returns>The created kernel.</returns>
        private static IKernel CreateKernel()
        {
            var kernel = new StandardKernel();
            try
            {
                kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
                kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
                RegisterServices(kernel);
                return kernel;
            }
            catch
            {
                kernel.Dispose();
                throw;
            }
        }

        /// <summary>
        /// Load your modules or register your services here!
        /// </summary>
        /// <param name="kernel">The kernel.</param>
        private static void RegisterServices(IKernel kernel)
        {
            kernel.Bind<EPINMiddleWareAPIContext>().ToSelf().InRequestScope();


        }        
    }
}
编辑: 基于Nkosi的解决方案,我尝试实现以下提供程序:

public class AuthenticationFilterProvider : System.Web.Http.Filters.IFilterProvider
    {
        private readonly Func<BasicAuthenticationAttribute> _authorizeViewFilterFactory;

        public AuthenticationFilterProvider(Func<BasicAuthenticationAttribute> authorizeViewFilterFactory)
        {
            this._authorizeViewFilterFactory = authorizeViewFilterFactory;
        }

        public IEnumerable<FilterInfo> GetFilters(HttpConfiguration configuration, HttpActionDescriptor actionDescriptor)
        {
            if (!actionDescriptor.GetCustomAttributes<BasicAuthenticationAttribute>().Any())
                return Enumerable.Empty<FilterInfo>();

            return new[]
            {
                new FilterInfo(this._authorizeViewFilterFactory(), FilterScope.Action)
            };
        }
    }
这对ninject有约束力:

kernel.Bind<System.Web.Http.Filters.IFilterProvider>().To<AuthenticationFilterProvider>();

但基本身份验证不会触发。

重构用户验证

如果您不打算使用该属性来修饰任何东西,并且只打算在配置中使用它,那么可以对其进行重构,使用构造函数注入工厂来获得服务

public class BasicAuthenticationAttribute : AuthorizationFilterAttribute {

    private const string Realm = "My Realm";
    readonly Func<IUserValidate> factory;

    public BasicAuthenticationAttribute(Func<IUserValidate> factory) {
        this.factory = factory;
    }

    public override void OnAuthorization(HttpActionContext actionContext) {
        //If the Authorization header is empty or null
        //then return Unauthorized
        if (actionContext.Request.Headers.Authorization == null) {
            actionContext.Response = actionContext.Request
                .CreateResponse(HttpStatusCode.Unauthorized);
            // If the request was unauthorized, add the WWW-Authenticate header 
            // to the response which indicates that it require basic authentication
            if (actionContext.Response.StatusCode == HttpStatusCode.Unauthorized) {
                actionContext.Response.Headers.Add("WWW-Authenticate",
                    string.Format("Basic realm=\"{0}\"", Realm));
            }
        } else {
            //Get the authentication token from the request header
            string authenticationToken = actionContext.Request.Headers
                .Authorization.Parameter;
            //Decode the string
            string decodedAuthenticationToken = Encoding.UTF8.GetString(
                Convert.FromBase64String(authenticationToken));
            //Convert the string into an string array
            string[] usernamePasswordArray = decodedAuthenticationToken.Split(':');
            //First element of the array is the username
            string username = usernamePasswordArray[0];
            //Second element of the array is the password
            string password = usernamePasswordArray[1];
            //call the login method to check the username and password
            IUserValidate uv = factory(); 
            if (uv.Login(username, password)) {
                var identity = new GenericIdentity(username);
                IPrincipal principal = new GenericPrincipal(identity, null);
                Thread.CurrentPrincipal = principal;
                if (HttpContext.Current != null) {
                    HttpContext.Current.User = principal;
                }
            } else {
                actionContext.Response = actionContext.Request
                    .CreateResponse(HttpStatusCode.Unauthorized);
            }
        }
    }
}

读取IDependencyResolver,将DI与web api集成,并根据需要通过类的构造函数注入和属性/过滤器的服务定位器模式来解决所需的依赖关系。@Nkosi我尝试过,但不知道如何将Dbcontext传递到WebApiConfig。为什么需要将Dbcontext传递到WebApiConfig?@Nkosi in为了查询数据库,我正在调用UserValidate的BasicAuthenticationAttribute。在UserValidate中,我将Dbcontext传递给构造函数。我如何调用UserValidate而不在BasicAuthenticationAttribute内部创建UserValidate。我可以将UserValidate绑定到BasicAuthenticationAttribute以调用Login吗?谢谢,我会尝试让您知道。顺便问一下,有必要在寄存器中创建内核吗?需要能够解析所需的类CreateKernel在WebApiConfig中由于私有而不可访问。在这种情况下,您使用的是什么DI容器,公开它并解析所需的类。@Cenk什么是引导程序类,它做什么?它是否设置了依赖项解析程序?
public class BasicAuthenticationAttribute : AuthorizationFilterAttribute {

    private const string Realm = "My Realm";
    readonly Func<IUserValidate> factory;

    public BasicAuthenticationAttribute(Func<IUserValidate> factory) {
        this.factory = factory;
    }

    public override void OnAuthorization(HttpActionContext actionContext) {
        //If the Authorization header is empty or null
        //then return Unauthorized
        if (actionContext.Request.Headers.Authorization == null) {
            actionContext.Response = actionContext.Request
                .CreateResponse(HttpStatusCode.Unauthorized);
            // If the request was unauthorized, add the WWW-Authenticate header 
            // to the response which indicates that it require basic authentication
            if (actionContext.Response.StatusCode == HttpStatusCode.Unauthorized) {
                actionContext.Response.Headers.Add("WWW-Authenticate",
                    string.Format("Basic realm=\"{0}\"", Realm));
            }
        } else {
            //Get the authentication token from the request header
            string authenticationToken = actionContext.Request.Headers
                .Authorization.Parameter;
            //Decode the string
            string decodedAuthenticationToken = Encoding.UTF8.GetString(
                Convert.FromBase64String(authenticationToken));
            //Convert the string into an string array
            string[] usernamePasswordArray = decodedAuthenticationToken.Split(':');
            //First element of the array is the username
            string username = usernamePasswordArray[0];
            //Second element of the array is the password
            string password = usernamePasswordArray[1];
            //call the login method to check the username and password
            IUserValidate uv = factory(); 
            if (uv.Login(username, password)) {
                var identity = new GenericIdentity(username);
                IPrincipal principal = new GenericPrincipal(identity, null);
                Thread.CurrentPrincipal = principal;
                if (HttpContext.Current != null) {
                    HttpContext.Current.User = principal;
                }
            } else {
                actionContext.Response = actionContext.Request
                    .CreateResponse(HttpStatusCode.Unauthorized);
            }
        }
    }
}
private static void RegisterServices(IKernel kernel) {
    kernel.Bind<EPINMiddleWareAPIContext>().ToSelf().InRequestScope();
    kernel.Bind<IUserValidate>().To<UserValidate>();
    kernel.Bind<BasicAuthenticationAttribute>().ToSelf();
}
public static class WebApiConfig {
    public static void Register(HttpConfiguration config) {

        var resolver = config.DependencyResolver; //Assuming one is set.
        var basicAuth = resolver.GetService(typeof(BasicAuthenticationAttribute)) as BasicAuthenticationAttribute;
        // Web API configuration and services
        config.Filters.Add(basicAuth);

        //...omitted for brevity