I'm currently working on a big project for car dealers and I have a dilemma.
Should I use ASP.NET Identity or old school FormsAuthentication?
I need to be able to login via 2 providers. First, the user is always in the database, but we check if it is a LDAP user, if so, authenticate it via LDAP (I use a WebService for that which has a Login method).
Here's my Login method:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginModel model)
{
if (ModelState.IsValid)
{
var userInDb = this.db.Users.FirstOrDefault(u => u.Username == model.username);
if (userInDb != null)
{
// USER EXISTS
if (userInDb.IsLdap)
{
try
{
// IS LDAP POWERED, IGNORE PASSWORD IN DB
using (var ws = WebServiceClient.Factory(model.GetDomain()))
{
// MAKE AUTH
var result = await ws.Login(model.GetUsername(), model.password);
if (result.Success)
{
// USER IS LEGAL
FormsAuthentication.SetAuthCookie(model.username, model.remember);
return RedirectToAction("Init");
}
else
{
// USER IS ILLEGAL
ModelState.AddModelError("", "Username or password invalid.");
}
}
}
catch (Exception ex)
{
// AN ERROR OCCURED IN CREATION OF THE WebService
ErrorUtils.Send(ex);
ModelState.AddModelError("", ex.Message);
}
}
else
{
// USER IS DB POWERED, CHECK THE PASSWORDS
var currentHash = userInDb.Password;
var isPasswordOkay = PasswordUtils.Validate(model.password, currentHash);
if (isPasswordOkay)
{
// USER PASSWORD IS LEGIT
FormsAuthentication.SetAuthCookie(model.username, model.remember);
return RedirectToAction("Init");
}
else
{
// BAD PASSWORD
ModelState.AddModelError("", "Username or password invalid.");
}
}
}
else
{
try
{
// USER DO NOT EXISTS IN DB
using (var ws = WebServiceClient.Factory(model.GetDomain()))
{
// MAKE AUTH
var result = await ws.Login(model.GetUsername(), model.password);
if (result.Success)
{
// USER IS LEGAL IN LDAP SO CREATE IT IN DB
var ldapUser = (AuthResponse.AuthResponseUser)result.User;
var name = ldapUser.DisplayName.Split(' ');
var user = new User()
{
Firstname = name[0],
Lastname = name[1],
ActivatedAt = DateTime.Now,
ModifiedAt = DateTime.Now,
Email = model.username,
IsLdap = true,
Username = model.username,
Password = "",
Notifications = NotificationType.All
};
// GET THE DEALER TO ADD IT TO THE USER RIGHT NOW
var dealer = this.db.BaseContexts.Find(ws.Dealer.Id);
user.BaseContexts.Add(dealer);
dealer.Users.Add(user);
try
{
this.db.Users.Add(user);
this.db.Entry(user).State = System.Data.Entity.EntityState.Added;
this.db.Entry(dealer).State = System.Data.Entity.EntityState.Modified;
await this.db.SaveChangesAsync();
FormsAuthentication.SetAuthCookie(model.username, model.remember);
return RedirectToAction("Init");
}
catch (Exception ex)
{
ErrorUtils.Send(ex);
ModelState.AddModelError("", "An error occured during user creation.");
}
}
else
{
// USER IS ILLEGAL
ModelState.AddModelError("", "Username or password invalid.");
}
}
}
catch (Exception ex)
{
// AN ERROR OCCURED IN CREATION OF THE WebService
ErrorUtils.Send(ex);
ModelState.AddModelError("", ex.Message);
}
}
}
return View(model);
}
How can I optimize it or implement the ASP.NET Identity in this? I read about Multi-Tenant but I'm not sure what it is.
I'm using FormsAuth right now and it works but seems to be very limited. For example, creating a user is difficult, however the Identity framework has the UserManager which is very helpful!
Clearly, I want something bulletproof to authenticate via DB or LDAP depending on the (bool)User.IsLdap
property. I though about creating a small class that act like an "Auth Service" but I can't find a way to structure it and make it fast.
EDIT: I'm aware of External Providers for Identity but not sure if I can create my own with my LDAP Auth.
Using ASP.NET Identity is the better way to go because it uses the OWIN stack instead of relying on system.web. This was done mostly for performance and seperation of concerns reasons. Also it's good to know that the newer versions of MVC are going this way.
What you are trying to do is use Mixed authentication of both Forms and Windows. While there are many ways to do this, often the easiest is to enable windows auth on the web server and then allow IIS to do the heavy lifting for you which would remove the need for the webservice. If that is the direction you want to go, you may want to have a look at this similar question that should get you headed in the right direction.
Mixed authentication for OWIN
Even if you don't do it exactly like the solution that is proposed, you would end up implementing your own OWIN middleware to do your authentication.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With