adding a custom rule in default asp.net login system - asp.net

Hi guys I'm working on a project in which we can disable our users. There is a column name status in user table that can be true or false. Now I want to add a new rule in default asp.net user login that if a user is disable(his column name status equals false), should not able to login with an error message that "Admin have disabled your account".
I have looked in,
ManageController.cs
IdentityConfig.cs
ManageViewModles.cs
IdentityModel.cs
but I didn't get any clue. How can I add this rule in my asp.net MVC-5 application

You could define a verification with an async function in your login view controller and call it on Login button press.
Good place to start: here
EDIT
Here some code sample you could have in your HomeController->Index Action. Note that this isn't async but you could implement an async action with your db call:
[HttpGet]
public ActionResult Index()
{
//Verification of user
//if true
return View();
//else false
return ErrorView(); //View that contains the error message
}

In login method of account controller i achieved it using this code.
I updated code in my switch(result) of case SignInStatus.Success:
case SignInStatus.Success:
var userID = SignInManager.AuthenticationManager.AuthenticationResponseGrant.Identity.GetUserId();
AspNetUser res = db.AspNetUsers.Where(x => x.Id == userID).Select(x => x).FirstOrDefault();
if (res.Status == "False")
{
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
// return RedirectToAction("Index", "Home");
ModelState.AddModelError("", "Admin has disabled your account.");
return View(model);
}
//remaining code here

Related

Asp.NET MVC 5 validate user by e-mail and password

I'm using a Asp.NET MVC 5 project that came with a Bootstrap 3 theme we bought and in its login method they just look for the user based on his e-mail, the password is not validated. Login method below:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(AccountLoginModel viewModel)
{
// Ensure we have a valid viewModel to work with
if (!ModelState.IsValid)
return View(viewModel);
// Verify if a user exists with the provided identity information
var user = await _manager.FindByEmailAsync(viewModel.Email);
var hashPass = new PasswordHasher().HashPassword(viewModel.Password); // this is a line I added which gerenates a different hash everytime
// If a user was found
if (user != null)
{
// Then create an identity for it and sign it in
await SignInAsync(user, viewModel.RememberMe);
// If the user came from a specific page, redirect back to it
return RedirectToLocal(viewModel.ReturnUrl);
}
// No existing user was found that matched the given criteria
ModelState.AddModelError("", "Invalid username or password.");
// If we got this far, something failed, redisplay form
return View(viewModel);
}
The line I'm trying to insert the password validation is the if (user != null). I tried using _manager.Find(email,password) but it doesn't work.
How can I login the user with his e-mail and validate the password?
That is because you are hashing the password before trying to find the user.
Do
var user = _manager.Find(viewModel.Email, viewModel.Password);
// If a user was found
if (user != null)
{
//...other code removed for brevity.
which is the standard way to do it.
-------Try this code------
var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);
switch (result)
{
case SignInStatus.Success:
return View("SuccessView");
case SignInStatus.Failure:
return View("LoginView");
}

Anti-Forgery Token was meant for a different claims-based user

I am working on a logout feature in the application we are using ASP.NET Identity login. I can login successfully but when I logout and then try to login again I get the following message:
The provided anti-forgery token was meant for a different claims-based user than the current user.
Here is my logout code:
public ActionResult Logout()
{
SignInManager.Logout();
return View("Index");
}
**SignInManager.cs**
public void Logout()
{
AuthenticationManager.SignOut();
}
After the user press the logout button he is taken to the login screen. The url still says "http://localhost:8544/Login/Logout". Since we are on the login screen maybe it should just say "http://localhost:8544/Login".
What worked for me was switching the order of the middlewares used. Add first app.UseAuthentication() and then the antiforgery stuff. This is how I did it:
app.UseAuthentication();
app.Use(next => ctx =>
{
var tokens = antiforgery.GetAndStoreTokens(ctx);
ctx.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken,
new CookieOptions() { HttpOnly = false });
return next(ctx);
});
Doing it the other way around creates a token that is not meant for authenticated users.
You are returning a View, rather than calling RedirectToAction(). So what is happening is the view is running under the context of the logout request, where the user is still logged in. They won't be logged out until the request finishes.
So, try
public ActionResult Logout()
{
SignInManager.Logout();
return RedirectToAction("Index", "Home");
}
I found that users were experiencing this issue when they would submit the login page when already authenticated. I replicated this error by:
Opening two tabs when logged in,
Logging out from one,
Reloading both,
Logging in to one,
Trying to log in with the other. The error occurred before entry to the POST: /Account/Login action.
The majority of my users use the web app on a mobile device, so it made sense that they had bookmarked the login page and pulled it up and submitted when they had a tab opened in the background already logged in. I also surmised that sometimes they would have a dormant tab loaded with the login form and just pull that tab up and submit.
I realize that there are many ways to solve this issue. I solved this with two changes:
I added a check on User.Identity.IsAuthenticated to my "GET: /Account/Login" action:
if (User.Identity.IsAuthenticated)
{
try
{
return RedirectToLocal(returnUrl);
}
catch
{
return RedirectToAction("index", "Home");
}
}
In my controller I created a "check if logged in" action:
[AllowAnonymous]
public JsonResult CheckLogedIn()
{
try
{
return Json(new { logged_in = User.Identity.IsAuthenticated }, JsonRequestBehavior.AllowGet);
}
catch
{
return Json(new { logged_in = false }, JsonRequestBehavior.AllowGet);
}
}
And I called it repeatedly in the view to redirect all open login forms away from the login page when already logged in:
<script type="text/javascript">
setInterval(function () {
$.ajax({
url: '#Url.Action("CheckLogedIn", "Account")',
type: "GET",
}).done(function (data) {
if (data.logged_in) {
window.location = '/';
}
});
}, 5000);
</script>
This worked well for me. Hope it helps you.
Try this:
public ActionResult Logout()
{
AuthenticationManager.SignOut();
Session.Abandon();
return RedirectToAction("Index");
}
That will reload your login page which will provide you a new CSRF token.
I've been getting this same error on the login for a LONG time now, but haven't been able to work out why. Finally I found it, so I'm posting it here (although it's a slightly different cause) in case someone else has it.
This was my code:
//
// GET: /login
[OutputCache(NoStore = true, Location = System.Web.UI.OutputCacheLocation.None)]
public ActionResult Login()
{
return View();
}
//
// POST: /login
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
if (!ModelState.IsValid)
{
return View(model);
}
//etc...
This worked fine for 99.99% of the logins, but every now & then I got the above-mentioned error, although I couldn't reproduce it, until now.
The error only happens when someone clicks the login button twice in quick succession. However, if I remove the AuthenticationManager.SignOut line in the Login action, then it's fine. I'm not sure why I put that line in there, but it's causing the issue - and removing it fixes the problem.
I didn't have the AuthenticationManager.SignOut command as Sean mentioned in my Login method. I was able to reproduce by clicking on the login button more than once before hte next View loads. I disabled the Login button after the first click to prevent the error.
<button type="submit" onclick="this.disabled=true;this.form.submit();"/>
Try this:
public ActionResult Login(string modelState = null)
{
if (modelState != null)
ModelState.AddModelError("", modelState );
return View();
}
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model)
{
AuthenticationManager.SignOut();
return RedirectToAction("Login", "Controller", new { modelState = "MSG_USER_NOT_CONFIRMED" });
}

Redirect users according to their Identity Role - ASP MVC 4 and 5

Hi I have an ASP MVC Application that using the MVC 5 Identity Roles, for the sake of simplicity I have 2 Identity Roles ("Admin" and "Staff"). Users in Role Admin can access the Admin Panel where they can create another users, and Users in Staff Role can only access Staff View.
I have no problem in assigning users to roles and apply [Authorise] to Controllers.
I want to redirect Users users to their relative Views after success log ins, so if a user is in Admin role, get's automatically redirected to admin panel or view and if a user in staff page redirected to staff view.
How do I apply this in my Login Controller? Thanks
If you're using UserManager and SignInManager (as per the default template) in your Controller:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> SignIn(SignInViewModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}
var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: true);
switch (result)
{
case SignInStatus.Success:
ApplicationUser user = await UserManager.FindAsync(model.Email, model.Password);
// Redirect to User landing page on SignIn, according to Role
if ((UserManager.IsInRole(user.Id, "User")))
{
return RedirectToAction("Index", "User");
}
if ((UserManager.IsInRole(user.Id, "Administrator")))
{
return RedirectToAction("Index", "Administrator");
}
return View(model);
// etc below - code to taste
case SignInStatus.LockedOut:
return View(model);
case SignInStatus.RequiresVerification:
return View(model);
case SignInStatus.Failure:
default:
return View(model);
}
}
You can simply redirect them from your login action method. So the pseudocode would be like below.
if (User.Role == "Admin")
{
//send him to Admin controller and index action
return RedirectToAction("ActionName","Controllername");
}
else if (User.Role == "Staff")
{
//send him to staff controller and index action
return RedirectToAction("ActionName","Controllername");
}
else
{
// if neither role show default public page
return RedirectToAction("ActionName","Controllername");
}
The comments are just to give you idea, It might vary in your application
if(UserType.Admin)
{
return RedirectToAction("HomeAdmin","Admin") // Admin Home
}
else if(UserType.Staff)
{
return RedirectToAction("HomeStaff","Staff")//Staff Home
}
And in your action methods
[Authorize]// Use this to authorize
public ActionResult HomeStaff()
{
}
[That's how I solved it, I didn't find any UserType or User.Role as stated in above solutions]

How to set up two-factor authentication in ASP.NET MVC 5.2.3 and Katana correctly?

In the code that you get in the ASP.NET MVC 5.2.3 templates with Visual Studio 2015 Community RC, if you run them as they came, and if you register with your email address (and not with an external service provider such as Facebook or Google or Linked In or Twitter), and then if you login into the website by entering your user name and password, it straight-away lets you login and does not trigger two-factor authentication. It just logs you in successfully.
Specifically, the PasswordSignInAsync method on the SignInManager always returns a SignInStatus of Success if you enter your correct user name and password. It never evaluates to SignInStatus.RequiresVerification.
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model,
string returnUrl)
{
if (!ModelState.IsValid)
{
return View(model);
}
// This doesn't count login failures towards account lockout
// To enable password failures to trigger account lockout,
// change to shouldLockout: true
var result = await SignInManager.PasswordSignInAsync(
model.Email, model.Password,
model.RememberMe, shouldLockout: true);
switch (result)
{
case SignInStatus.Success:
// if I sign-in with my correct user name
// and password, the flow-of-control always
// comes here. The SignInStatus never evaluates
// to RequiresVerification
return RedirectToLocal(returnUrl);
case SignInStatus.LockedOut:
return View("Lockout");
case SignInStatus.RequiresVerification:
// the flow-of-control never reaches here
return RedirectToAction("SendCode",
new
{
ReturnUrl = returnUrl,
RememberMe = model.RememberMe
});
case SignInStatus.Failure:
default:
ModelState.AddModelError("", "Invalid login attempt.");
return View(model);
}
}
This happens even though the default code has got two-factor authentication enabled and set up as indicated by the following snippets of code.
In Startup.ConfigureAuth
app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie,
TimeSpan.FromMinutes(5));
app.UseTwoFactorRememberBrowserCookie(
DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie);
In ApplicationUserManager.Create, the factory method.
// 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.
manager.RegisterTwoFactorProvider("Phone Code",
new PhoneNumberTokenProvider<ApplicationUser>
{
MessageFormat = "Your security code is {0}"
});
manager.RegisterTwoFactorProvider("Email Code",
new EmailTokenProvider<ApplicationUser>
{
Subject = "Security Code",
BodyFormat = "Your security code is {0}"
});
var container = Unity.Container;
manager.EmailService = container.Resolve<EmailService>();
manager.SmsService = container.Resolve<SmsService>();
I've got my EmailService and SmsService set up in a Unity container and they're configured properly.
What else do I need to do to set it up correctly? I have read this article and a few pieces of documentation from the MSDN, and a few forums posts on other websites about setting this up, but I am not very certain if I am missing something.
This guy isn't called / redirected to from anywhere. I guess this is what's missing.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> EnableTwoFactorAuthentication()
{
await UserManager.SetTwoFactorEnabledAsync(User.Identity.GetUserId(),
true);
var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
if (user != null)
{
await SignInManager.SignInAsync(user, isPersistent: false,
rememberBrowser: false);
}
return RedirectToAction("Index", "Manage");
}
It does seem that I am missing the part where I have to specifically have the user call the EnableTwoFactorAuthentication action as there is currently no call to it, but I can't be sure how that should integrate with the rest of the login workflow.
Click f12 from your browser and delete application Cookies

Custom redirection in ASP.NET MVC 4

I'm trying to build a two-step custom registration for users in my ASP.NET MVC 4 application. This involves redirecting users after registration to the Edit view in the User Controller. I've tweaked the code in the stock Account Controller template to achieve this.
public ActionResult Register(RegisterModel model)
{
if (ModelState.IsValid)
{
// Attempt to register the user
try
{
WebSecurity.CreateUserAndAccount(model.UserName, model.Password);
WebSecurity.Login(model.UserName, model.Password);
return RedirectToAction("Edit", "User", new { id = WebSecurity.CurrentUserId });
}
catch (MembershipCreateUserException e)
{
ModelState.AddModelError("", ErrorCodeToString(e.StatusCode));
}
}
return View(model);
}
However when I run this I get a 404 on the address bar it shows
http://localhost:17005/User/Edit/-1
Which means it's going into the Edit action of user controller, but then ending up with a Id of -1. Any help would be appreciated.
Membership.GetUser().ProviderUserKey
Alternatively you could not pass a user id to the edit action and have the code use the currently logged in user.
RedirectToAction("Edit", "User");
In your user controller
[Authorize]
public ActionResult Edit()
{
object userId = Membership.GetUser().ProviderUserKey;
}
Please excuse brevity as I am currently on my mobile

Resources