簡體   English   中英

通過ASP.Identity表自動訪問ASP.NET WEPAPI 2.2

[英]Autofac into ASP.NET WEPAPI 2.2 with Asp.Identity Tables

我根據本教程編寫了兩個非常受支持的WebAPI。 現在的事情是,我還不需要IoC / DI,但是我正在編寫一個Web API,並試圖從頭開始整合它。

我對存儲庫/服務/工作單元模式有很好的了解,但是在移植Identity的全部時遇到錯誤。 特別是使用OAuthConfiguration類的啟動時,如下所示:

錯誤

None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'Vender.Providers.AuthorizationServerProvider' can be invoked with the available services and parameters:
Cannot resolve parameter 'Vender.Services.ApplicationClientService appClientsService' of constructor 'Void .ctor(Vender.Services.ApplicationClientService, Vender.Data.Context.ApplicationUserManager)'.

帶有異常的方法 (嘗試解析兩個提供程序時會產生上述錯誤)

    public static void ConfigTokenGeneration(IAppBuilder app, IContainer container)
    {
        app.CreatePerOwinContext(ApplicationDbContext.Create);


        var oAuthServerOptions = new OAuthAuthorizationServerOptions()
        {

            AllowInsecureHttp = ApiSettings.AllowInsecureHttp,
            TokenEndpointPath = new PathString("/token"),
            AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(ApiSettings.AccessTokenValidTime),
            Provider = container.Resolve<IOAuthAuthorizationServerProvider>(),
            AccessTokenFormat = new JwtFormatProvider(ApiSettings.ApiAddress),
            RefreshTokenProvider = container.Resolve<IAuthenticationTokenProvider>()
        };

        app.UseOAuthAuthorizationServer(oAuthServerOptions);
    }

異常類

public class AuthorizationServerProvider : OAuthAuthorizationServerProvider
{
    private readonly ApplicationClientService _appClientsService;
    private readonly ApplicationUserManager _userManager;

    public AuthorizationServerProvider(ApplicationClientService appClientsService,
                                       ApplicationUserManager userManager)
    {
        _appClientsService = appClientsService;
        _userManager = userManager;
    }
    public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
    {
        string clientId;
        string clientSecret;

        if (!context.TryGetBasicCredentials(out clientId, out clientSecret))
        {
            context.TryGetFormCredentials(out clientId, out clientSecret);
        }

        if (context.ClientId == null)
        {
            //Remove the comments from the below line context.SetError, and invalidate context 
            //if you want to force sending clientId/secrets once obtain access tokens. 
            context.Validated();
            context.SetError("invalid_clientId", "ClientId should be sent.");
            return Task.FromResult<object>(null);
        }

        var client = _appClientsService.FindApplicationClient(context.ClientId);


        if (client == null)
        {
            context.SetError("invalid_clientId", $"Client '{context.ClientId}' is not registered in the system.");
            return Task.FromResult<object>(null);
        }

        if (client.ApplicationType == ApplicationTypes.NativeConfidential)
        {
            if (string.IsNullOrWhiteSpace(clientSecret))
            {
                context.SetError("invalid_clientId", "Client secret should be sent.");
                return Task.FromResult<object>(null);
            }
            else
            {
                if (client.Secret != Hash.FromString(clientSecret))
                {
                    context.SetError("invalid_clientId", "Client secret is invalid.");
                    return Task.FromResult<object>(null);
                }
            }
        }

        if (!client.Active)
        {
            context.SetError("invalid_clientId", "Client is inactive.");
            return Task.FromResult<object>(null);
        }

        context.OwinContext.Set<string>("as:clientAllowedOrigin", client.AllowedOrigin);
        context.OwinContext.Set<string>("as:clientRefreshTokenLifeTime", client.RefreshTokenLifeTime.ToString());

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

    public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
    {

        var allowedOrigin = context.OwinContext.Get<string>("as:clientAllowedOrigin") ?? "*";
        context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { allowedOrigin });

        IDictionary<string, string> userData = new Dictionary<string, string>();
        var user = await _userManager.FindAsync(context.UserName, context.Password);

        if (user == null)
        {
            context.SetError("invalid_grant", "apiError.invalidUsernameOrPassword");
            return;
        }



        var oAuthIdentity = await user.GenerateUserIdentityAsync(_userManager, "JWT");
        var userProps = new AuthenticationProperties(userData);
        var ticket = new AuthenticationTicket(oAuthIdentity, userProps);
        context.Validated(ticket);
        /*
        //  Get userManager to test credentials against
        //
        var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
        // find user by username first            
        ApplicationUser user = await userManager.FindByEmailAsync(context.UserName);

        if (user != null)
        {
            var validCredentials = await userManager.FindAsync(context.UserName, context.Password);

            if (await userManager.IsLockedOutAsync(user.Id))
            {
                context.SetError("invalid_grant", "This account has been locked out.  Please come back later.");
                return;
            }
            else if (await userManager.GetLockoutEnabledAsync(user.Id) && validCredentials == null)
            {
                // Record the failure which also may cause the user to be locked out
                await userManager.AccessFailedAsync(user.Id);

                string message;

                if (await userManager.IsLockedOutAsync(user.Id))
                {
                    message = "apiError.accountLockout";
                }
                else
                {
                    int accessFailedCount = await userManager.GetAccessFailedCountAsync(user.Id);
                    int attemptsLeft = Convert.ToInt32(ConfigurationManager.AppSettings["MaxFailedAccessAttemptsBeforeLockout"].ToString()) - accessFailedCount;

                    message = string.Format("apiError.lockoutAttempts{0}", attemptsLeft);

                }
                context.SetError("invalid_grant", message);
                return;
            }
            else if (validCredentials == null)
            {
                context.SetError("invalid_grant", "Invalid username or password, please try again.");
                return;
            }
            else
            {
                if (!user.EmailConfirmed)
                {
                    context.SetError("invalid_grant", "Email has not yet been confirmed.");
                    return;
                }

                user.LastLoginDateUtc = System.DateTime.UtcNow;
                user.SuccessLoginCount++;

                var loginInfo = new LoginTracker();
                loginInfo.ApplicationUser = user;
                loginInfo.LoginTimeUtc = DateTime.UtcNow;


            }
        }
        else
        {
            context.SetError("invalid_grant", "Invalid username or password, please try again.");
            return;
        }
        */

    }

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

    }
}

AutoFac Builder

    private static IContainer RegisterServices(ContainerBuilder builder)
    {
        builder.RegisterApiControllers(Assembly.GetExecutingAssembly());

        // EF HomeCinemaContext
        builder.RegisterType < ApplicationDbContext>()
               .As<DbContext>()
               .InstancePerRequest();

        builder.RegisterType<DbFactory>()
            .As<IDbFactory>()
            .InstancePerRequest();

        builder.RegisterType<UnitOfWork>()
            .As<IUnitOfWork>()
            .InstancePerRequest();

        builder.RegisterGeneric(typeof(EntityBaseRepository<>))
               .As(typeof(IEntityBaseRepository<>))
               .InstancePerRequest();

        builder.RegisterType<ApplicationUserManager>()
           .SingleInstance();


        builder.RegisterType<AddressService>()
            .As<IAddressService>()
            .InstancePerRequest();

        builder.RegisterType<ApplicationClientService>()
            .As<IApplicationClientService>()
            .InstancePerRequest();

        builder.RegisterType<RefreshTokenService>()
            .As<IRefreshTokenService>()
            .InstancePerRequest();

        builder.RegisterType<AuthorizationServerProvider>()
            .AsImplementedInterfaces<IOAuthAuthorizationServerProvider, ConcreteReflectionActivatorData>().SingleInstance();

        builder.RegisterType<RefreshTokenProvider>()
            .AsImplementedInterfaces<IAuthenticationTokenProvider, ConcreteReflectionActivatorData>().SingleInstance();




        Container = builder.Build();
        return Container;
    }

應用經理類

public class ApplicationUserManager : UserManager<ApplicationUser>
{
    public ApplicationUserManager(ApplicationDbContext identityContext)
        : base(new UserStore<ApplicationUser>(identityContext))
    {
    }

    public ApplicationUserManager(IUserStore<ApplicationUser> store, IDataProtectionProvider dataProtectionProvider)
        : base(store)
    {
        UserValidator = new UserValidator<ApplicationUser>(this)
        {
            AllowOnlyAlphanumericUserNames = false,
            RequireUniqueEmail = true
        };

        // Configure validation logic for passwords
        PasswordValidator = new PasswordValidator
        {
            RequiredLength = 6,
            RequireNonLetterOrDigit = false,
            RequireDigit = true,
            RequireLowercase = true,
            RequireUppercase = true,
        };

        // Configure user lockout defaults
        UserLockoutEnabledByDefault = false;
        //DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5);
        //MaxFailedAccessAttemptsBeforeLockout = 5;

        // Register two factor authentication providers. This application uses Phone and Emails as a step of receiving a code for verifying the user
        // You can write your own provider and plug it in here.
        RegisterTwoFactorProvider("Phone Code", new PhoneNumberTokenProvider<ApplicationUser>
        {
            MessageFormat = "Your security code is {0}"
        });

        RegisterTwoFactorProvider("Email Code", new EmailTokenProvider<ApplicationUser>
        {
            Subject = "Security Code",
            BodyFormat = "Your security code is {0}"
        });


        UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>(dataProtectionProvider.Create("ASP.NET Identity"));
    }
}

應用程序客戶服務類別

public class ApplicationClientService : IApplicationClientService
{
    private readonly IEntityBaseRepository<ApplicationClient> _appClientRepository;
    private readonly IUnitOfWork _unitOfWork;

    public ApplicationClientService(IEntityBaseRepository<ApplicationClient> appClientRepository,
                          IUnitOfWork unitOfWork)
    {
        _appClientRepository = appClientRepository;
        _unitOfWork = unitOfWork;
    }

    public async Task<bool> CreateApplicationClientAsync(ApplicationClient newToken)
    {
        _appClientRepository.Add(newToken);
        return await _unitOfWork.CommitAsync() > 0;
    }

    public Task<ApplicationClient> FindApplicationClientAsync(string clientId)
    {
        var refreshToken = _appClientRepository.GetAll().FirstOrDefault(x => x.ClientId == clientId);
        return Task.FromResult(refreshToken);
    }

    public ApplicationClient FindApplicationClient(string clientId)
    {
        var refreshToken = _appClientRepository.GetAll().FirstOrDefault(x => x.ClientId == clientId);
        return refreshToken;
    }

}

應用程序客戶端服務接口

public interface IApplicationClientService
{
    Task<bool> CreateApplicationClientAsync(ApplicationClient newToken);

    ApplicationClient FindApplicationClient(string clientId);

}

現在,我一直在搜索,直到發現才有用,而且我想知道我在這里需要做什么來修復我的接口/類,以便在實例化oAuthServerOptions時可以解決它們。

我使用AutoFac Builder的此解決方案解決了該問題,因此您應該制作所有單個實例,因為請求前依賴項錯誤

        var builder = new ContainerBuilder();
        var config = GlobalConfiguration.Configuration;
        builder.RegisterApiControllers(Assembly.GetExecutingAssembly());

        builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().SingleInstance();
        builder.RegisterType<DbFactory>().As<IDbFactory>().SingleInstance();
        builder.RegisterType<ApplicationDbContext>().AsSelf().SingleInstance();
       // rest of code as singleInstance 
        builder.Register<IdentityFactoryOptions<ApplicationUserManager>>(c => new IdentityFactoryOptions<ApplicationUserManager>() { DataProtectionProvider = new DpapiDataProtectionProvider("Elhag.WebAPI") });
        builder.RegisterType<ApplicationUserManager>().AsSelf().SingleInstance();

        builder.Register(c=>new AuthorizationServerProvider(c.Resolve<ApplicationUserManager>())).AsImplementedInterfaces().SingleInstance();
        builder.Register(c => new UserStore<ApplictionUser>(c.Resolve<ApplicationDbContext>())).AsImplementedInterfaces().SingleInstance();
        builder.Register(c => HttpContext.Current.GetOwinContext().Authentication).As<IAuthenticationManager>();
        IContainer container = builder.Build();
        config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
       return container;

並且您可以解決所需的所有依賴關系,但不要根據autofac網站直接使用容器,您應該使用container lifeTimeScope,因此我將使用container.BeginLifetimeScope()。Resolve <您的類型>();

var oAuthServerOptions = new OAuthAuthorizationServerOptions()
    {

        AllowInsecureHttp = ApiSettings.AllowInsecureHttp,
        TokenEndpointPath = new PathString("/token"),
        AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(ApiSettings.AccessTokenValidTime),
        Provider = container.BeginLifetimeScope().Resolve<IOAuthAuthorizationServerProvider>(),
        AccessTokenFormat = new JwtFormatProvider(ApiSettings.ApiAddress),
        RefreshTokenProvider = container.BeginLifetimeScope().Resolve<IAuthenticationTokenProvider>()
    };

我測試正常並且工作正常...希望對您有所幫助

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM