I am working on a legacy MVC application which initially had forms authentication via a custom class and implementation. I have modified it and utilised Asp.Net Identity which is working as expected.
My requirement now is that this MVC application no longer should have direct access to the database. So I have removed the connection string from the web.config and have been looking at making all database calls via calls to my web service (Asp.Net Web Api).
I have custom classes for:
UserStore
RoleStore
etc
Please note I have a custom user class as it is a custom user table.
Questions
1) Is the correct way to achieve my goal? It's likely I will be overriding many methods which had previously used the IdentityDBContext such as:
public override Task<CustomUser> FindByIdAsync(int usrID)
public override Task<Customer> FindByNameAsync(string userName)
2) I am finding that
FindByNameAsync()
is working as expected and the user is being passed to the method however FindByIdAsync() is passing userid as 0. Why would FindByIdAsync() not be passing my actual userid?
To call FindByIdAsync() I am implementing a UserStore:
public class CustomUserStore : UserStore
<
CustomUser,
CustomRole,
int,
CustomUserLogin,
CustomUserRole,
CustomUserClaim
>
{
and then overriding FindByIdAsync():
public override Task<CustomUser> FindByIdAsync(int usrID)
{
var response = client.GetAsync("api/user/" + usrID).Result.Content;
return response.ReadAsAsync<CustomUser>(
new List<MediaTypeFormatter> {
new XmlMediaTypeFormatter(),
new JsonMediaTypeFormatter()
});
//return base.FindByIdAsync(userId);
}
The issue is that usrID is 0.
I now have this working, so my mvc application is using AspNet.Identity but for all the database calls it is calling my api. The solution was indeed to implement IUserStore (and other interfaces as required) and there are a lot of answers and guides on the Internet for this. A good starting point is:
https://learn.microsoft.com/en-us/aspnet/identity/overview/extensibility/overview-of-custom-storage-providers-for-aspnet-identity
Related
I need to build a custom user password check in an application implemented in asp.net MVC 5 and using Asp.Net Identity 2.
I read in a stackoverflow post (Writing a custom IUserPasswordStore and SignInManager.PasswordSignInAsync in Identity 2.1) that I only need to override the CheckPasswordAsync method in UserManager.
I try to override this method in IdentityConfig.cs file. Here is the code that I add to the ApplicationUserManager class just for test this solution:
public override async Task<bool> CheckPasswordAsync(ApplicationUser user, string password)
{
return await Task.Run(() => {
return true;
});
}
The problem is that this code is never run in the login process, and the login always fail. To sign in the user I’m using the SignInManager.PasswordSignInAsync to log in the user, this is the default when creating a new web application in asp.net MVC 5. Shouldn’t this method call the ApplicationUserManager. CheckPasswordAsync? Or there is another configuration needed to this work?
It should work. I've just used the standard ASP.NET MVC template, updated all the libraries involved through NuGet, and it must work.
I guess the problems is the way you are overriding the method.
In your ApplicationUserManager try to change your code like this:
public override Task<bool> CheckPasswordAsync(ApplicationUser user, string password)
{
return Task.FromResult<bool>(true);
}
or:
public override Task<bool> CheckPasswordAsync(ApplicationUser user, string password)
{
return Task.Run(() => MyCheckPasswordAsync());
}
private bool MyCheckPasswordAsync()
{
return true;
}
and you will see it goes through:
The problem was that I was trying to login with a user that do not exists in the system.
The SignInManager.PasswordSignInAsync never invoke the ApplicationUserManager. CheckPasswordAsync if the user not exists in the user store repository.
In conclusion, I have to store the users in my application or implement a custom user store mechanism.
This may not be a direct answer however it provides a full solution to the problem. He implements a custom authorisation filter which you can then customise to do what you want.
https://weblog.west-wind.com/posts/2013/Apr/18/A-WebAPI-Basic-Authentication-Authorization-Filter
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
public class BasicAuthenticationFilter : AuthorizationFilterAttribute
It can then be used like this instead of the [Authorize] attribute
[MyBasicAuthenticationFilter]
public class QueueController : ApiController
I'm trying to follow the Bootstrap ServiceStack code from http://bootstrapapi.apphb.com/
I can register a new user, but soon I do everything I want (create a new user on my table that extends the UserAuth table) in the CreateUserAuth() method from my CustomUserAuth it redirects to http://localhost:50447/api/register
I want to go back to the Home Controller...
What is the simple way to accomplish this?
In the docs, under Authentication, this is not very explicit, and I'm using the latest version to date: v4.0.30 and I'm implementing a custom CredentialsAuthProvider.
You can use the ?Continue=/path QueryString parameter to specify where it should redirect to.
If you're using your own custom UserAuth tables (i.e instead of integrating with the existing UserAuth tables) you should subclass OrmLiteAuthRepository<T,T> class including your custom POCO's, e.g see the source for OrmLiteAuthRepository:
public class OrmLiteAuthRepository
: OrmLiteAuthRepository<UserAuth, UserAuthDetails>, IUserAuthRepository
{
public OrmLiteAuthRepository(IDbConnectionFactory dbFactory)
: base(dbFactory) { }
}
50,000ft overview:
Web API (OWIN) hosted by IIS.
In OWIN Middleware I do a bunch of things (API Key validation in order to authenticate a request, create principles, etc...).
I am using Unity as my container. Once I actually get to my controllers, I am injecting a service class which abstracts my repository from my controllers. In the service layer I do things like audit tracking, history logging and the like so that everywhere I inject my service classes, I get the added benefit.
This all works, life is good, yada yada yada.
Until...
I have a custom header value (X-OnBehalfOf) which the caller of the API populates with the user ID that a particular request is being performed by. This is a requirement of the application and its implementation is pretty straight forward.
I can easily retrieve this value from anywhere I have access to the Request (OWIN Middleware, controller, etc...). The problem I am trying to solve however comes in when trying to get that value in my service layer.
Since I am using my container to resolve the instance of the service class, I intitially though the best solution would be to implement something like IHeaderProvider and inject that into the constructor of the service class, but I cannot seem to figure out how to get a reference to the Request in that class since it is out of the pipeline.
I am sure there is an obvious way to do this but I keep running into issues. Does anyone know how to get that reference without having to new it up so that I can leverage my DI container to do the work for me?
It would appear I just needed to put it down on paper. This is how I solved it:
Container:
container.RegisterType<IHeaderProvider, HeaderProvider>(new HierarchicalLifetimeManager());
container.RegisterType<HttpContextBase>(new InjectionFactory(c => new HttpContextWrapper(HttpContext.Current)));
IHeaderProvider:
public interface IHeaderProvider
{
Guid GetOnBehalfOf();
}
HeaderProvider:
public class HeaderProvider : IHeaderProvider
{
private readonly HttpContextBase _httpContextBase;
public HeaderProvider(HttpContextBase httpContextBase)
{
_httpContextBase = httpContextBase;
}
public Guid GetOnBehalfOf()
{
var xOnBehalfOf = _httpContextBase.Request.Headers.Get("X-OnBehalfOfId");
Guid userId;
if (string.IsNullOrWhiteSpace(xOnBehalfOf))
throw new Exception("Missing user ID");
if (Guid.TryParse(xOnBehalfOf, out userId))
{
return userId;
}
throw new Exception("Invalid user ID");
}
}
I'm building a multi-tenant MVC app where there's a single app pool and single database. I have a Tenant table, and each of my models has a TenantId identified.
Each Tenant has a string "Url" that identifies the full URL used to access that tenant's data.
I can access this from my BaseController with the following (rough approximation):
HttpRequest request = HttpContext.Current.Request;
Uri requestUrl = request.Url;
_tenant = _tenantService.GetTenantByUrl(requestUrl);
Now, I'm at a point where I need to pass the Tenant into the service layer to perform business logic. One way I can do this is to go across every single method across all services (~200 methods) and add a Tenant parameter. I'd have to touch every call to the service layer, and every service layer method. This would work, but it's tedious and muddles the code.
For example, one of my methods before:
public void DeleteUserById(int userId)
{
using (var db = CreateContext())
{
var user = db.Users.FirstOrDefault(u => u.UserId.Equals(userId));
InternalDeleteUser(db, user);
}
}
After (if I pass in the Tenant):
public void DeleteUserById(Tenant tenant, int userId)
{
using (var db = CreateContext())
{
var user = tenant.Users.FirstOrDefault(u => u.UserId.Equals(userId));
InternalDeleteUser(db, user);
}
}
What I'm trying to achieve (by setting the tenant from my BaseController, one layer up):
public void DeleteUserById(int userId)
{
using (var db = CreateContext())
{
var user = _tenant.Users.FirstOrDefault(u => u.UserId.Equals(userId));
InternalDeleteUser(db, user);
}
}
Is there any way I can use my BaseService (all other services inherit from this) or some other pattern to define the Tenant from the Controller, and have the service methods pick it up, without passing it as a parameter to each one? This way I need only touch the base controller (or maybe even global.asax), and nothing else.
Put simply: How can I make an object accessible to all services by defining it from an MVC controller, without passing it directly to the service?
I guess what you´re saying about having a base service (see Layer Supertype) makes sense. That base class will have a dependency on an interface defined in the same service layer (e.g. IUserSession, IContext or whatever) and that interface will have a method or property that will return your Tenant.
The implementation of this interface will reside in your web application and it will do something as what you described, obtaining the data from the HttpContext.
If you have a background process, console application or whatever that does not run on a web context, you will have a different implementation that will create the Tenant based on any other criteria that you want.
So to summarize, you will have in your service layer:
abstract class BaseService
{
protected IContext Context {get; private set;}
public BaseService(IContext context)
{
Context = context;
}
}
public interface IContext
{
Tenant GetTenant();
}
Then in your web layer you´ll have:
public IWebContext : IContext
{
public Tenant GetTenant()
{
//your code to return create the tenant based on the url.
}
}
Hope this helps.
I have the same 'problem' since I'm building a multi tenant app as well. However, I solved it quite simple, IMO: every repository/service has defined a TenantId property, that must be set when that service is used. TenantId is a value object and it will throw if null.
Now, the point is any of the repos/services can be used outside the request, for example in a background thread or app. I am using a message driven approach so any required info (like tenant id) is part of the message and thus available for the consumer of the service (the message handler). Another benefit is testability.
I advice against coupling your service to a request specific object like HttpContext, Session or Cache.
In our ASP.NET MVC project we are using Ninject to resolve our dependencies needed by the controllers.
One of these dependencies is the current user HttpContext.Current.User.Identity. If the user is authenticated we would like to instantiate a user object and several services which relies on it. But we would like to do this not manually but let ninject inject these instances to the controller.
So we get into trouble now, since a url can be located without being authenticated of course. Then ninject tries to resolve the instances before asp.net can redirect to the login page.
I can think of the solution, that we configure ninject do just inject when user is authenticated:
kernel.Bind<User>().ToMethod(GetUser).When(context => HttpContext.Current.User.Identity.IsAuthenticated).InRequestScope();
The problem here is that even if the user is not authenticated ninject instantiates a default object, so my services crashes or needs to check the instance anyhow.
Null checks would me much more acceptable but I wouldn't like to activate AllowNullInjection setting of Ninject.
So my question is whats the best practise for doing such conditional things?
Are there Ninject features I could use in these cases or shouldn't I inject these dependencies anyway?
I assume you are talking about a situation where a non-authenticated user could try to navigate to a page that normally requires authentication, but without first going through the login process. Ninject would then be unable to inject the current user object into the controller because it's not yet known and will throw an exception.
I can see 2 options:
The first option is instead of injecting the current user, create a factory or provider that retrieves the current user details and inject this instead. The controller can then call the provider to get the current user and if the user is unavailable you can redirect to the login page.
public OrdersController(IUserProvider userProvider)
{
this.userProvider = userProvider
}
public void DoSomething()
{
var user = this.userProvider.GetCurrentUser();
if (user == null)
RedirectToLogin();
// continue doing something
}
public class UserProvider : IUserProvider
{
public User GetCurrentUser() { ... }
}
The problem with this option is that you'll need to do this potentially in many controllers (it's a "cross cutting concern") and you don't want to have to repeat the code that does the redirect over and over. Instead, a second option would be to use the Decorator design pattern to create an interceptor that checks for logged in users before forwarding on to the real controller.
The way I've done something similar in the past is using the Ninject Interception Extension to create an attribute that marks which controllers require authentication, like this (bit psuedo-codey):
public class AuthenticationInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
bool authenticated = // ... get the current user ...
if (authenticated)
invocation.Proceed();
else
RedirectToLoginPage(); // however you want to do this
}
}
public class RequiresAuthenticationAttribute : InterceptAttribute
{
public override IInterceptor CreateInterceptor(IProxyRequest request)
{
return request.Context.Kernel.Get<AuthenticationInterceptor>();
}
}
[RequiresAuthentication]
public class OrdersController : IOrdersController
{
// assume you've already been authenticated
}
The interceptor will automatically be created whenever a class that's decorated with RequiresAuthentication is created and the current user credentials will be checked. If they are invalid, the request will be forwarded to the login page, otherwise it will continue as normal. This one interceptor can then be written and tested once whilst being used in many places without duplicating code.
Just as a simple auth and non auth answer that some may find useful.
kernel.Bind<ICustomUser>()
.To<User>()
.When(ctx => HttpContext.Current.User.Identity.IsAuthenticated)
.InRequestScope();
kernel.Bind<ICustomUser>()
.To<Guest>()
.When(ctx => !HttpContext.Current.User.Identity.IsAuthenticated)
.InRequestScope();
Otherwise anything more complex Adam Rodgers awnser is better :)