I have a project where I use MVC5 with WebAPI. Authentication uses Owin. I want to setup Ninject dependency resolver. I tried soultions for MVC5, for MVC5 with Owin, for WebApi for WebAPI with Owin. But I can't combine them. Does anybody have the steps for MVC5+WebApi+Owin+Ninject bundle?
One of the last solution to make it workable for WebApi I followed here:
https://github.com/ninject/Ninject.Web.Common/wiki/Setting-up-a-OWIN-WebApi-application
I added latest NuGet packages.
My Startup class:
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
var webApiConfiguration = new HttpConfiguration();
WebApiConfig.Register(webApiConfiguration);
app.UseNinjectMiddleware(CreateKernel).UseNinjectWebApi(webApiConfiguration);
ConfigureAuth(app);
}
private static StandardKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Load(Assembly.GetExecutingAssembly());
return kernel;
}
}
WebApiConfig. I didn't add any routing configurations. As it is added in Global.asax:
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
var webApiConfiguration = new HttpConfiguration();
app.UseNinjectMiddleware(CreateKernel).UseNinjectWebApi(webApiConfiguration);
ConfigureAuth(app);
}
private static StandardKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Load(Assembly.GetExecutingAssembly());
return kernel;
}
}
WebApi with routings(and removed routing registration in Global.asax) it doesn't work too. On each request to ANY WebApi I have "{"Message":"Authorization has been denied for this request."}":
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
var webApiConfiguration = new HttpConfiguration();
// Web API configuration and services
// Configure Web API to use only bearer token authentication.
webApiConfiguration.SuppressDefaultHostAuthentication();
webApiConfiguration.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
webApiConfiguration.MapHttpAttributeRoutes();
webApiConfiguration.Routes.MapHttpRoute("DefaultApi", "api/{controller}/{action}/{id}", new { id = RouteParameter.Optional });
app.UseNinjectMiddleware(CreateKernel).UseNinjectWebApi(webApiConfiguration);
ConfigureAuth(app);
}
private static StandardKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Load(Assembly.GetExecutingAssembly());
return kernel;
}
}
ConfigureOAuth. I'm using two way authentication one based on cookie another based on Tokne. One suitable for WebApi another for MVC:
public void ConfigureAuth(IAppBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Login"),
Provider = new CookieAuthenticationProvider
{
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<UserManager, User>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager,DefaultAuthenticationTypes.ApplicationCookie))
}
});
PublicClientId = "self";
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(PublicClientId),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
AllowInsecureHttp = true
};
}
And my API controller.
[Authorize(Roles = "Admin")]
public class AdminPanelController : ApiController
{
private readonly IAdminPanelService _service;
public AdminPanelController(IAdminPanelService service)
{
_service = service;
}
}
I always have exception that AdminPanelController should be parameterless. If I add any routing to WebApiConfig I will have the same exception for AdminPanelController and not authorized for other(though Bearer Token generates and pass to WebApi controllers)
To get Dependency Injection to work with Web API you should implemented an IDependencyResolver for Ninject and apply it to HttpConfiguration.DependencyResolver.
See more here. You can even find a NuGet package here.
Related
I am getting this error while configuring Autofac with ASP.NET WebAPI.
An error occurred when trying to create a controller of type 'UserController'. Make sure that the controller has a parameterless public constructor.
Startup.cs
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
var file = HostingEnvironment.MapPath("~/log4net.config");
if (file != null)
{
var configFile = new FileInfo(file);
if (configFile.Exists)
XmlConfigurator.ConfigureAndWatch(configFile);
else
BasicConfigurator.Configure();
}
else
{
BasicConfigurator.Configure();
}
var builder = new ContainerBuilder();
var config = new HttpConfiguration();
// Register your Web API controllers.
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterWebApiFilterProvider(config);
builder.RegisterModule(new WebModule(app));
// Register your MVC controllers.
builder.RegisterControllers(Assembly.GetExecutingAssembly());
// OPTIONAL: Register model binders that require DI.
builder.RegisterModelBinders(Assembly.GetExecutingAssembly());
builder.RegisterModelBinderProvider();
// OPTIONAL: Register web abstractions like HttpContextBase.
builder.RegisterModule<AutofacWebTypesModule>();
// OPTIONAL: Enable property injection in view pages.
builder.RegisterSource(new ViewRegistrationSource());
// OPTIONAL: Enable property injection into action filters.
builder.RegisterFilterProvider();
// register config
builder.Register(ct => config).AsSelf().SingleInstance();
HelpPageConfig.Register(config);
var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
app.UseAutofacMiddleware(container);
app.UseAutofacWebApi(config);
app.UseAutofacMvc();
WebApiConfig.Register(config);
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseWebApi(config);
config.EnsureInitialized();
}
}
Global.asax.cs
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
}
WebModule.cs
public class WebModule : Module
{
private readonly IAppBuilder _app;
public WebModule(IAppBuilder app)
{
_app = app;
}
protected override void Load(ContainerBuilder builder)
{
// ---- Utilities -----------------------------------
builder.RegisterType<Log4NetLogger>()
.As<ILogger>().SingleInstance();
builder.RegisterType<DataAccessConfigurationSettings>()
.As<IDataAccessSettings>().SingleInstance();
builder.RegisterType<ApplicationServicesConfigurationSettings>()
.As<IApplicationServicesSettings>().SingleInstance();
builder.RegisterType<ValidationExceptionHandler>()
.As<IExceptionHandler<ValidationException>>().SingleInstance();
builder.RegisterType<SqlExceptionHandler>()
.As<IExceptionHandler<SqlException>>().SingleInstance();
builder.RegisterType<GeneralExceptionHandler>()
.As<IExceptionHandler<Exception>>().SingleInstance();
// ---- Business ------------------------------------
builder.RegisterType<UserBusiness>()
.As<IUserBusiness>().InstancePerRequest();
// ---- Validator -----------------------------------
builder.RegisterType<UserSignupModelValidator>()
.AsSelf().SingleInstance();
// ---- Controllers -----------------------------------
builder.RegisterType<DeflateCompressionActionFilter>()
.AsWebApiActionFilterFor<UserController>().InstancePerRequest();
base.Load(builder);
}
}
UserController.cs
[RoutePrefix("api/User")]
public class UserController : ApiController
{
private readonly IUserBusiness _userBusiness;
public UserController(IUserBusiness userBusiness)
{
_userBusiness = userBusiness;
}
...
}
I believe I'm missing some minor thing which I have no idea, any help would be appreciated.
Have a look on this answer: MVC Web API not working with Autofac Integration
Maybe you just need to do set you container like it was described on the link above:
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
GlobalConfiguration.Configuration.DependencyResolver =
new AutofacWebApiDependencyResolver(container);
Theoretically you get a different exception but it could also be the case.
I have a ASP.NET Core 1.0 Solution with 3 projects (Web, Console Application, DataAccessLayer).
I use ASP.NET Core Identity and Entity Framework Core (SQL Server - Code First).
In my Console Application (Used for background tasks), I want to create users, but how I can have access to UserManager object in a Console Application (Or in a .NET Core Class Library) ?
In a controller class, it's easy with Dependency Injection :
public class AccountController : Controller {
private readonly UserManager<ApplicationUser> _userManager;
public AccountController(UserManager<ApplicationUser> userManager, SignInManager<ApplicationUser> signInManager)
{
_userManager = userManager;
}
//...
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Register(RegisterViewModel model)
{
var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
var result = await _userManager.CreateAsync(user, model.Password);
//...
}
How I can do the equivalent in a Console Core Application ?
Thanks to Tseng's answer I ended up with this code. Just in case if someone would need:
public class Program
{
private interface IUserCreationService
{
Task CreateUser();
}
public static void Main(string[] args)
{
var services = new ServiceCollection();
services.AddDbContext<ApplicationDbContext>(
options =>
{
options.UseSqlServer("Server=(localdb)\\mssqllocaldb;Database=my-app-db;Trusted_Connection=True;MultipleActiveResultSets=true");
});
// Authentification
services.AddIdentity<ApplicationUser, IdentityRole>(opt =>
{
// Configure identity options
opt.Password.RequireDigit = false;
opt.Password.RequireLowercase = false;
opt.Password.RequireUppercase = false;
opt.Password.RequireNonAlphanumeric = false;
opt.Password.RequiredLength = 6;
opt.User.RequireUniqueEmail = true;
})
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.AddScoped<IUserCreationService, UserCreationService>();
// Build the IoC from the service collection
var provider = services.BuildServiceProvider();
var userService = provider.GetService<IUserCreationService>();
userService.CreateUser().GetAwaiter().GetResult();
Console.ReadKey();
}
private class UserCreationService : IUserCreationService
{
private readonly UserManager<ApplicationUser> userManager;
public UserCreationService(UserManager<ApplicationUser> userManager)
{
this.userManager = userManager;
}
public async Task CreateUser()
{
var user = new ApplicationUser { UserName = "TestUser", Email = "test#example.com" };
var result = await this.userManager.CreateAsync(user, "123456");
if (result.Succeeded == false)
{
foreach (var error in result.Errors)
{
Console.WriteLine(error.Description);
}
}
else
{
Console.WriteLine("Done.");
}
}
}
}
In my Console Application (Used for background tasks), I want to create users, but how I can have access to UserManager object in a Console Application (Or in a .NET Core Class Library) ?
Same as you do it in ASP.NET Core. You just need to bootstrap it yourself. Inside your Main (which is the console applications composition root - the earliest point where you can set up your object graph).
Here you create a ServiceCollection instance, register the services and build the container, then resolve your app entry point. From there, anything else goes via DI.
public static int Main(string[] args)
{
var services = new ServiceCollection();
// You can use the same `AddXxx` methods you did in ASP.NET Core
services.AddIdentity();
// Or register manually
services.AddTransient<IMyService,MyService();
services.AddScoped<IUserCreationService,UserCreationService>();
...
// build the IoC from the service collection
var provider = services.BuildServiceProvider();
var userService = provider.GetService<IUserCreationService>();
// we can't await async in Main method, so here this is okay
userService.CreateUser().GetAwaiter().GetResult();
}
public class UserCreationService : IUserCreationService
{
public UserManager<ApplicationUser> userManager;
public UserCreationService(UserManager<ApplicationUser> userManager)
{
this.userManager = userManager;
}
public async Task CreateUser()
{
var user = new ApplicationUser { UserName = "TestUser", Email = "test#example.com" };
var result = await _userManager.CreateAsync(user, model.Password);
}
}
In practice the first class you resolve wouldn't be your UserCreationService but some MainApplication class, which is the core of your application and responsible for keeping the application alive as long as the operation happens, i.e. if its a background worker you run some kind of host (Azure Web Job Host etc.) which keeps the application running so it can receive events from outside (via some message bus) and on each event starts a specific handler or action, which in turn resolves other services etc.
I know this answer is late, but other people might benefit.
You are seriously overcomplicating things using services etc.
You can just do:
var userStore = new UserStore<ApplicationUser>(new ApplicationDbContext());
var manager = new ApplicationUserManager(userStore);
var result = await manager.Create(user, password);
If you still want all the password validation functionality just add it to the constructor of ApplicationUserManager
I am currently using asp.net identity for identity management, IdentityServer3 for oauth2, Castle Windosr for IOC and the DataProtectorTokenProvider for email tokens. My code works fine when hosted in IIS but I get the error No IUserTokenProvider is registered when self hosted within a windows service. My startup code is:
public class Startup
{
public static IDataProtectionProvider DataProtectionProvider { get; private set; }
public void Configuration(IAppBuilder app)
{
DataProtectionProvider = app.GetDataProtectionProvider();
var httpConfig = new HttpConfiguration();
app.UseIdentityServer();
ioc = new IoC();
app.UseIdentityAdministration(ioc);
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "Cookies"
});
app.UseCors(CorsOptions.AllowAll);
app.UseWebApi(httpConfig);
}
}
In my user controller, the constructor has this code:
var dataProtectorProvider = Startup.DataProtectionProvider;
if (dataProtectorProvider != null)
{
var dataProtector = dataProtectorProvider.Create(RC.ResetPasswordTokenPurpose, RC.ConfirmEmailTokenPurpose);
_userManager.UserTokenProvider = new DataProtectorTokenProvider<IdentityUser, int>(dataProtector)
{
TokenLifespan = TimeSpan.FromMinutes(SC.TokenLifespan)
};
}
_userManager is the Asp.net identity user manager and is provide by IOC. It all works fine when hosted in IIS but when self hosted i.e.
internal void StartService()
{
var options = new StartOptions();
options.Urls.Add(ConfigurationManager.AppSettings["PublicOrigin"]);
webApp = WebApp.Start(options, builder => new Startup().Configuration(builder));
}
I get the above error. Any help would be greatly appreciated.
I'm experimenting with self hosted OWIN for a WebApi/Entity Framework project
I've created the Startup Class and configured both OWIN and WebApi using UseOAuthBearerAuthentication and UseOAuthAuthorizationServer with Provider defined to a Class deriving from OAuthAuthorizationServerProvider
Provider = new ApplicationOAuthServerProvider() // :OAuthAuthorizationServerProvider
this Class overrides
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{}
validate the user creates a ClaimsIdentity returning a token encoding the associated claims in my case NameIdentifier, Name and Role (Role is "Admin")
Everything works as expected and token is returned.
Now I'd like to take advantage of the associated claims from inside an ApiController.
Problem is User.Identityobject has only AuthentiationType isAuthenticated and Name properties all associated Claims are not there and I can't do much with Name property.
I see that by using
[Authorize (Roles="Admin")]
I'm able to access the ApiController so the Role Claim is available somewhere but the other claims I'm not able to access;
is there a way to solve my issue???
[Authorize (Roles="Admin")]
public class TestController : ApiController
{
public async Task<Account> Get()
{
var principal = User.Identity;
.... find and return data for user ID
}
}
Here are the Classes I've used
public class Startup
{
// This method is required.
public void Configuration(IAppBuilder app)
{
// Use cors on server level
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
// Configure OWIN to authenticate incoming requests.
ConfigureAuth(app);
// Use the extension method provided by the WebApi.Owin library.
app.UseWebApi(ConfigureWebApi());
}
private void ConfigureAuth(IAppBuilder app)
{
// Make sure a single instance of an EF context is created per OwinContext.
app.CreatePerOwinContext<ApplicationDbContext>(ApplicationDbContext.Create);
var OAuthOptions = new OAuthAuthorizationServerOptions{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthServerProvider(),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
// Debug Only
AllowInsecureHttp = true
};
// The server is added to the options object, which specifies other configuration items,
// and which is then passed into the middleware pipeline.
app.UseOAuthAuthorizationServer(OAuthOptions);
// Indicate that we want to return Bearer Tokens
// passing the default implementation for OAuthBearerAuthenticationOptions,
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
}
private HttpConfiguration ConfigureWebApi()
{
var config = new HttpConfiguration();
//Add JSON formetters
// Configure api routes
config.Routes.MapHttpRoute(
"DefaultApi",
"api/{controller}/{id}",
new { id = RouteParameter.Optional });
return config;
}
}
ApplicationOAuthServerProvider Class
public class ApplicationOAuthServerProvider : OAuthAuthorizationServerProvider
{
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
// This call is required...
await Task.FromResult(context.Validated());
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
if (context.Password == "Password")
{
// Create or retrieve a ClaimsIdentity to represent the
// ClaimsIdentity is created to represent the user data, including any Claims the user should have.
ClaimsIdentity identity = new ClaimsIdentity(context.Options.AuthenticationType);
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, "120"));
identity.AddClaim(new Claim(ClaimTypes.Name, context.UserName));
identity.AddClaim(new Claim(ClaimTypes.Role, "Admin"));
// ClaimsIdentity is be encoded into an Access Token
context.Validated(identity);
}
else
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
context.Rejected();
}
}
}
I have a webforms project, but am using WebAPI for web services. I am trying to implement Autofac. I am getting:
'MyController' does not have a default constructor
According to the Autofac documentation I have the configuration correct but obviously there is a problem. I am using Visual Studio 2010/.Net 4. Here is my Application_Start
private void Application_Start(object sender, EventArgs e)
{
//This enables api controllers in a separate class library
GlobalConfiguration.Configuration.Services.Replace(typeof(IAssembliesResolver), new AssembliesResolver());
GlobalConfiguration.Configuration.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
//Elmah for webapi
GlobalConfiguration.Configuration.Filters.Add(new ElmahHandleErrorApiAttribute());
var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);
var builder = new ContainerBuilder();
//Register DbContext
builder.RegisterType<MyDbContext>()
.As<IMyDbContext>()
.InstancePerRequest();
//Register service layer
var businessLayer = Assembly.GetExecutingAssembly();
builder.RegisterAssemblyTypes(AppDomain.CurrentDomain.GetAssemblies())
.Where(t => t.Name.EndsWith("Service"))
.AsImplementedInterfaces();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterWebApiFilterProvider(GlobalConfiguration.Configuration);
var container = builder.Build();
_containerProvider = new ContainerProvider(container);
var webApiResolver = new AutofacWebApiDependencyResolver(container);
GlobalConfiguration.Configuration.DependencyResolver = webApiResolver;
}
A typical api controller looks like this:
[Authorize]
public class MyController : ApiController
{
public IMyService context { get; set; }
public MyController(IMyService context)
{
this.context = context;
}
// GET api/dostuff
/// <summary>
/// Get a list of all dtos
/// </summary>
/// <returns></returns>
public IEnumerable<MyDto> Get()
{
try
{
return context.MyDtos.ToList();
}
catch (Exception ex)
{
var message = string.Format("{0} {1} HTTP/1.1 {2} Exception: {3}", Request.Method, Request.RequestUri, HttpStatusCode.MethodNotAllowed, ex.Message);
var errorMessage = new System.Web.Http.HttpError(message) { { "ErrorCode", 405 } };
throw new HttpResponseException(ControllerContext.Request.CreateErrorResponse(HttpStatusCode.MethodNotAllowed, errorMessage));
}
}
}
If you have your api controllers in a different assembly than your web project, then you need to need to tell Autofac where to find your controllers with changning:
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
To
builder.RegisterApiControllers(typeof(MyController).Assembly);
This will instruct Autofac to scan the assembly of MyController and register all ApiController derived types what it founds there.