I'm having some trouble with my application, because I need 2 ways to log in: form (user + password) or route (passing user unique identifier).
I configured FormsAuthentication and it's working for user + password method, but when I try to log in through unique identifier, I can't redirect to my HomeController.
User + Password:
[HttpPost]
public string Authenticate(string usuario, string senha, string returnUrl)
{
var authenticated = this.UsuarioService.Acessar(usuario, senha, out int codUsuario);
if (authenticated)
{
var user = this.UsuarioService.Buscar(codUsuario);
MontaPermissoes(ref user);
FormsAuthentication.SetAuthCookie(JsonConvert.SerializeObject(user), false);
if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/")
&& !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\"))
return returnUrl;
else
return Url.Action("Index", "Home", new { id = "" });
}
return null;
}
Unique Identifier:
[HttpGet]
private RedirectToRouteResult Autenticacao(Guid uniqId)
{
var usuario = UsuarioService.Buscar(uniqId);
if (usuario != null)
{
MontaPermissoes(ref usuario);
FormsAuthentication.SetAuthCookie(JsonConvert.SerializeObject(usuario), false);
return RedirectToAction("Index", "Home", new { culture = RouteData.Values["culture"] });
}
return RedirectToAction("Index", "Login", new { culture = RouteData.Values["culture"] });
}
Using user + password, I just return next URL to redirect via Javascript, but unique identifier log in will be used by another application, using the same database.
This problem could be IIS related, your application has to have two authentication options enabled.
FormsAuthentication
Anonymous Authentication
With anonymous authentication enabled the application can allow Anonymous calls.
You can add an AllowAnonymous attribute to your controller or specific controller methods to make sure that FormsAuthentication won't be triggered.
[AllowAnonymous]
public class MyController: Controller {}
Related
I have created this login post method in my login controller, what it does is that it takes the email submitted (no password) and we run the email in the stored procedure to check if the user exists, if they do Set Authentication Cookie. Now I am looking to add on to this. Here is my current code:
WebServiceController service = new WebServiceController();
[HttpPost]
public ActionResult Index(LoginClass model, string returnUrl)
{
if (!ModelState.IsValid)
{
ModelState.AddModelError("", "The email provided is incorrect.");
return View(model);
}
List<UserClass> user = service.loginUser(model.Email);
if(user.Count > 0)
{
FormsAuthentication.SetAuthCookie(model.Email, true);
if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/")
&& !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\"))
{
return Redirect(returnUrl);
}
return RedirectToAction("Index", "Home");
}
ModelState.AddModelError("", "The user name or password provided is incorrect.");
return View(model);
}
Now service.loginUser also returns a int value called divisionID and a user can have multiple divisionID, I would like the divisionID to be the users Role. My question is how would I go about implementing that?
I have a login controller with a post action which redirects to home page after successful login. I am using following code for redirection, which works well in Chrome and Firefox. but doesn't redirect in IE and EDGE, and response cookie not set
private ActionResult RedirectToLocal(string returnUrl)
{
if (Url.IsLocalUrl(returnUrl))
{
return Redirect(returnUrl);
}
else
{
return RedirectToRoute("default", new { controller = "", action = "" });
}
}
My Login action
public IActionResult Login(string userName, string password)
{
try
{
if (string.IsNullOrEmpty(userName) || string.IsNullOrEmpty(password))
throw new InvalidOperationException("Username/Password can not be empty");
var session = CreateSession(userName, password);
var returnUrl = Request.Query["returnUrl"];
return RedirectToLocal(returnUrl);
}
catch (Exception ex)
{
ModelState.AddModelError("Login", ex.Message);
}
return View();
}
I am using my own session management for which I set session cookies like following
CookieOptions option = new CookieOptions();
option.Path = AppPath;
option.Domain = AppHost;
httpContextAccessor.HttpContext.Response.Cookies.Append(AppSessionToken, "SomeSessionId", option);
After searching a lot for exact answer, I found that Internet Explorer (all versions) doesn't allow you to specify a domain of localhost, a local IP address or machine name. When you do, Internet Explorer simply ignores the cookie.
So I removed following line
option.Domain = AppHost;
from my codes and everything start working as expected on both IE and EDGE.
Since you didn't post your route mapping from Startup.cs, I am not sure why it didn't work for you. Maybe you shouldn't override the controller and action parameter by passing new { controller = "", action = "" } into the RedirectToRoute() method?
Instead, have you tried just calling the method with the route name, like
return RedirectToRoute("default");
Or, you can use RedirectToAction()
if (Url.IsLocalUrl(returnUrl))
{
return Redirect(returnUrl);
}
// action, controller and route values
return RedirectToAction("index", "home", new { area = "" });
I have a MVC and a Web API projects within the same solution, on the MVC project I have a very small Admin area protected with a login and password (just for one user). On this area I get the data on clinet side using API calls.
This is my Login function:
public ActionResult SubmitLogin(string UserName, string Password)
{
if (ModelState.IsValid)
{
if (UserName == "xxxxx" && Password == "yyyyy")
{
FormsAuthentication.SetAuthCookie(UserName, true);
return RedirectToAction("Index", #"Admin/Users");
}
}
var errors = (from value in ModelState.Values
from error in value.Errors
select error.ErrorMessage).ToList();
if (errors.Count == 0)
{
errors.Add("UserName or Password are incorrect");
}
ViewBag.Message = errors;
return View("Index");
}
The Login form works fine, the issue is with the API calls, my API controller is [Authorize] but when I make a request:
self.getUsers = function (callback) {
$.get("../MySite.API/Users/GetUsers/", callback);
}
I get a 401 error.
I understand I have to somehow send the AuthCookie with the AJAX request but I'm not sure how.
Any help would be appreciated.
I have implemented a custom UserStore, it implements IUserStore<DatabaseLogin, int> and IUserPasswordStore<DatabaseLogin, int>.
My Login action method is as below:
if (ModelState.IsValid)
{
if (Authentication.Login(user.Username, user.Password))
{
DatabaseLogin x = await UserManager.FindAsync(user.Username, user.Password);
DatabaseLogin Login = Authentication.FindByName(user.Username);
if (Login != null)
{
ClaimsIdentity ident = await UserManager.CreateIdentityAsync(Login,
DefaultAuthenticationTypes.ApplicationCookie);
AuthManager.SignOut();
AuthManager.SignIn(new AuthenticationProperties
{
IsPersistent = false
}, ident);
return RedirectToAction("Index", "Home");
}
}
else
{
ModelState.AddModelError("", "Invalid Login");
}
}
return View();
In the custom authentication class that I wrote, Authentication, I have a Login method that works fine, also FindByName method returns an app user. But if I try to SignIn with that login, the user isn't recognized as authenticated and HttpContext.User.Identity is always null, so I imagine that I have to try UserManager.FindAsync.
This method calls FindByNameAsync and GetPasswordHashAsync, and it always return null.
public Task<DatabaseLogin> FindByNameAsync(string userName)
{
if (string.IsNullOrEmpty(userName))
throw new ArgumentNullException("userName");
return Task.FromResult<DatabaseLogin>(Authentication.FindByName(userName));
}
public Task<string> GetPasswordHashAsync(DatabaseLogin user)
{
if (user == null)
throw new ArgumentNullException("user");
return Task.FromResult<string>(user.Password);
}
And the Authentication.FindByName
public static DatabaseLogin FindByName(string name)
{
string GetUserQuery = string.Format(
"USE db;SELECT principal_id AS id, name as userName, create_date AS CreateDate, modify_date AS modifyDate FROM sys.database_principals WHERE type='S' AND authentication_type = 1 AND name = '{0}'"
, name);
DatabaseLogin user;
using (var db = new EFDbContext())
{
user = db.Database.SqlQuery<DatabaseLogin>(GetUserQuery).FirstOrDefault();
}
user.Password = Convert.ToBase64String(Encoding.ASCII.GetBytes("pass"));
return user;
}
As you can see I'm using database users, I'm not sure how I can retrieve a hashed password for them. For now, I'm just storing the Base65 of the correct password!
I have no idea where I'm going wrong, any guidance is welcome.
Short answer: nothing's wrong. User is authenticated in other action methods, but apparently not in the current action method.
This is the process that I followed, maybe it will help you debug your app.
After reading the source code, FindAsync first calls FindByNameAsync, followed by CheckPasswordAsync which references VerifyPasswordAsync. So it should be fine If I could override VerifyPasswordAsync.
I created a custom password hasher that implements IPasswordHasher, and registered it in the create method of my UserManager like this:
manager.PasswordHasher = new DbPasswordHasher();
So by now, I can get my user from UserManager.FindAsync, but it turned out that it doesn't matter where you get the user since HttpContext.User.Identity is still null! My mistake was that I didn't notice the user isn't authenticated in the current action, in other action methods it works as expected!
when I was writing ASP.NET applications I used the Forms Authentication with my custom login page, like so:
Once login is a success I checked him as authenticated:
FormsAuthentication.RedirectFromLoginPage(userId.ToString(), true);
In order to check if a user is logged in, I had a class that inherited from a base page and all pages inherited from it, which contained a method that returned a bool after checking if the user is authenticated, with the following command:
return HttpContext.Current.User.Identity.IsAuthenticated;
Now, I'm doing an ASP.NET MVC application, and was wondering what is the best was to do that on MVC?
Thanks
ok MVC is very simple and similar
for your question you can use like .......
in your controller
public ActionResult LogOn()
{
return View();
}
//
// POST: /Account/LogOn
[HttpPost]
public ActionResult LogOn(LogOnModel model, string returnUrl)
{
if (ModelState.IsValid)
{
var userInfo = new UserInfo()
{
UserName = model.UserName,
Password = model.Password,
};
var service = new CSVService();
if(service.ValidateUser(userInfo))
{
FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/")
&& !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\"))
{
return Redirect(returnUrl);
}
else
{
return Redirect("~/");
}
}
else
{
ModelState.AddModelError("", "The user name or password provided is incorrect.");
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
The best way to authenticate website / web-application is using the Membership which is provided by Microsoft built in for Easy-ness .
From this you can do following things(features)
it maintains Log-in status (you don't have to bother about Authentication).
It allows to provide Roles & Users and Assigning permission who can see which page
(Page Restriction)
It provides built-in Stored Procedures and UI tools like Log-in, Log-out,user,Password Recovery, Etc elements. & Highly secure (Hack-Proof)
for more info:
Walk through Membership (MSDN)