Web-Api authentication problems - asp.net-web-api

This is my first ASP.NET project and I want to make a easy login.
I tried this: Link
but I can't understand basic things:
public class AccountController : ApiController
{
public bool Post(LogOnModel model)
{
if (model.Username == "john" && model.Password == "secret")
{
FormsAuthentication.SetAuthCookie(model.Username, false);
return true;
}
return false;
}
}
1) How to code a correct call to this controller?
2) Should not somethings like "credentials" or "Username + PW" instead a LogOnModel?

Related

Is validating a userId (or any other data extracted from an authentication token) necessary?

In my controller action as have something like this:
[HttpGet]
[ActionName("approve")]
[Authorize(Policy = "Approve")]
public IActionResult GetEntitiesToBeApproved()
{
var stringUserId = User.Claims.FirstOrDefault(c => c.Type == "http://schemas.microsoft.com/identity/claims/objectidentifier")?.Value;
Guid.TryParse(stringUserId, out var userId);
if (userId == default(Guid))
{
return StatusCode((int)HttpStatusCode.BadRequest, ConstantValues.InvalidUserId);
}
//service calls etc.
return Ok();
}
Is there any point in checking that the userId is valid (non-default) or can I skip it?
You can skip it, Authorize filter attribute check it for You.

I Want to execute second Login(contactnumber,password) but after passing the argument it is still calling the list login method How to resolve this?

I Want to execute second Login(contactnumber,password) but after passing the argument it is still calling the list login method How to resolve this?
[HttpGet]
public IEnumerable<UserDetail> Login()
{
using (HeandSheEntities entities = new HeandSheEntities())
{
return entities.UserDetails.ToList();
}
}
[System.Web.Http.AcceptVerbs("GET")]
[System.Web.Http.HttpGet]
public HttpResponseMessage Login(String ContactNumber, String Password) {
{ String Upass = encryption(Password);
using (HeandSheEntities entities = new HeandSheEntities())
{
bool userphone = entities.UserDetails.Any(u => u.UserContactNumber.Equals(ContactNumber));
bool userpass = entities.UserDetails.Any(u => u.UserPassword.Equals(Upass));
if (ModelState.IsValid && userphone && userpass)
{
var user = entities.UserDetails.FirstOrDefault(u => u.UserContactNumber.Equals(ContactNumber));
if (user != null)
return Request.CreateResponse(HttpStatusCode.OK, user, new System.Net.Http.Headers.MediaTypeHeaderValue("application/json"));
else
return Request.CreateResponse(HttpStatusCode.BadRequest, "Either Contact Number or password is not correct", new System.Net.Http.Headers.MediaTypeHeaderValue("application/json"));
}
else
{
return Request.CreateResponse(HttpStatusCode.BadRequest, "Either Contact Number or password is not correct", new System.Net.Http.Headers.MediaTypeHeaderValue("application/json"));
}
}
}
}
You use the same name for both action methods with the same http verb. You cannot overload action methods. See here and here. Semantically you should use POST http method for changing state (for example logging user) and it will work.
[HttpPost]
public HttpResponseMessage Login(String ContactNumber, String Password)

Request.IsAuthenticated Return False all the time

I am having an issue with my Request.IsAuthenticated always return false. I am setting the AuthCookie
CurrentRequest currentRequest = null;
if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/")
&& !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\"))
{
return Redirect(returnUrl);
} else if (login.ValidateUser(acct.UserName, acct.Password))
{
FormsAuthentication.SetAuthCookie(acct.UserName, true); //Edit on 11/12 #11:08
currentRequest = new CurrentRequest();
SessionWrapper.currentRequest = currentRequest;
return RedirectToAction("About", "Home");
}
//This is a partial login page that is supposed to display login or Logoff.
#using KMSS.Helper;
// this is always false
#if (Request.IsAuthenticated) //Same issue with User.Identity.IsAuthenticated
{
if (SessionWrapper.currentRequest != null)
{
<text> Welcome <strong> #SessionWrapper.currentRequest.Username </strong>
[#Html.ActionLink("Sign Off", "Logoff", "Account")]
</text>
} else {
#: [ #Html.ActionLink("Sign In", "Login", "Account") ]
}
} else
{
#:[ #Html.ActionLink("Sign In", "Login", "Account") ]
}
After reading online, I created a class with a bool value and tries to use that class instead. However, I am getting the object is not set to instance of a new variable exception.
Here is how I had it set up:
//Partial Login page
#model KMSS.Helper.ViewModelAuthenticate;
// this is always false
#if (Model.IsAuthenticated)
//The model is null even though I create create a reference in the Login Method i.e.
(ViewModelAuthenticate auth = new ViewModelAuthenticate();
{
if (SessionWrapper.currentRequest != null)
{
<text> Welcome <strong> #SessionWrapper.currentRequest.Username </strong>
[#Html.ActionLink("Sign Off", "Logoff", "Account")]
</text>
} else {
#: [ #Html.ActionLink("Sign In", "Login", "Account") ]
}
} else
{
#:[ #Html.ActionLink("Sign In", "Login", "Account") ]
}
//Here is the class
public class ViewModelAuthenticate
{
public bool IsAuthenticate { get; set; }
}
//Here is where I am initializing the class in the controller
public ActionResult Login()
{
ViewModelAuthenticate auth = new ViewModelAuthenticate();
auth.IsAuthenticate = false;
return View();
}
//I tried this inside and outside of Login, and it is called before the partial login view. However, I am still getting the object is not set to instance of a new variable exception.
What am I doing wrong here? Your help will be appreciated.
//Showing the authentication section of the config file.
<authentication mode="Forms">
<forms loginUrl="~/Account/Login" timeout="2880" slidingExpiration="true" />
</authentication>
I replaced my authentication section with this sample that a sample that I found here. It is working now.
Looking at your code, I feel that there is more going on here than you are showing us. Specifically, the variables CurrentRequest and SessionWrapper, setting them to null on the beginning of the Action method call, etc. I would suggest trying a basic, bare bones example in your project and then begin to add items back in as needed. No AJAX, only full page post back to the server from your login form. Such an example would look like:
Login View Model
public class LoginViewModel{
[Required]
public string UserName {get;set;}
[Required]
public string Password {get;set;}
}
Login POST Action method
[HttpPost]
public ActionResult Login(LoginViewModel model, string returnUrl){
if(!ModelState.IsValid){
return View();
}
if(!provider.ValidateUser(model.UserName, model.Password){
ModelState.AddModelError("", "The username/password combination does not match");
return View();
}
FormAuthentication.SetAuthCookie(model.UserName, true);
if(!string.IsNullOrEmpty(returnUrl) && Url.IsLocalUrl(returnUrl){
return Redirect(returnUrl);
}
return RedirectToAction("About", "Home");
}
About View
#if(Request.IsAuthenticated){
<b>It WORKS!!</b>
}else{
<b>Nope, still not working</b>
}
I was testing and I set my time back a few days. For someone reason it caused this issue after putting the date back it was fine. I assume windows forms had the old date (which was todays date) cached so I assume it was expired. Just a thought about the matter.

issue on redirecting on log in page when already log in in Mvc3

im having a hard time trying to solve this issue. when i input a username and a password ive always redirect again in log in page. why this happen???
here's my code in login
account controller:
[HttpPost]
public ActionResult LogOn(LogOnModel model, string returnUrl)
{
if (ModelState.IsValid)
{
if (Membership.ValidateUser(model.UserName, model.Password))
{
FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/")
&& !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\"))
{
return Redirect(returnUrl);
}
if (Roles.IsUserInRole("Employer"))
{
return RedirectToAction("CustomerIndex", "Customer");
}
else if (Roles.IsUserInRole("Worker"))
{
return RedirectToAction("WorkerIndex", "Worker");
}
else if (Roles.IsUserInRole("Administrator"))
{
return RedirectToAction("ClientIndex", "Client");
}
else
{
return View(model);
}
}
else
{
ModelState.AddModelError("", "The user name or password provided is incorrect.");
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
thanks.for those who willing to help :)
Looking at your code there are 3 possible cases when this can happen:
Model validation failed -> for example the user didn't provide a username
The user provided incorrect credentials and the ValidateUser method returned false
Credential validation succeeded but the user is not in any of the roles Employer, Worker or Administrator.
Put a breakpoint in your code to see which is your case and act accordingly.

MVC Role based routing clarification

Small Question at the end of a very long explanation ...
Assuming the Admin User belonging to Admin Role and the Regular User belonging to User Role attempt to access the Index page with the following route registered in Global.asax.
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
new[] {"tst.Controllers"}
);
In the HomeController, the Index Action Method is decorated with the Authorize attribute.
[Authorize]
public ActionResult Index()
{
ViewBag.Message = "Welcome to ASP.NET MVC!";
return View();
}
Forcing the anonymous user to logon.
If the Admin User logs in with his/her credentials, I would like to redirect him/her to the Index Action Method in the HomeController located in the Admin area.
If a Regular user logs in, I would like to redirect him/her to the Index Action Method in the HomeController located in the User area.
I have the following code in UserAreaRegistration.cs
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"User",
"Profile/{action}",
new { area = AreaName, Controller = "Home", action = "Index" },
new { RoleConstraint = new RoleConstraint()},
new[]{ "tst.Areas.User.Controllers"}
);
}
and the following code for AdminAreaRegistration.cs
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Admin",
"Profile/{action}",
new { area = AreaName, Controller = "Home", action = "Index" },
new { RoleConstraint = new RoleConstraint()},
new[]{ "tst.Areas.Admin.Controllers"}
);
}
Where the RoleConstraint is defined as follows
public class RoleConstraint: IRouteConstraint
{
public bool Match(
HttpContextBase httpContext,
Route route,
string parameterName,
RouteValueDictionary values,
RouteDirection routeDirection)
{
RoleProvider rp = new tst.Providers.CustomRoleProvider();
string[] roles = rp.GetRolesForUser(httpContext.User.Identity.Name);
if (roles != null && roles.Length > 0)
{
string roleName = roles[0];
string areaName = route.Defaults["area"].ToString();
return areaName == roleName;
}
return false;
}
}
The stock standard LogOn Action Method in the AdminController in the main Controllers folder...
[HttpPost]
public ActionResult LogOn(LogOnModel model, string returnUrl)
{
if (ModelState.IsValid)
{
if (Membership.ValidateUser(model.UserName, model.Password))
{
FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
if (Url.IsLocalUrl(returnUrl)
&& returnUrl.Length > 1
&& returnUrl.StartsWith("/")
&& !returnUrl.StartsWith("//")
&& !returnUrl.StartsWith("/\\"))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}
else
{
ModelState.AddModelError("", "The user name or password is incorrect.");
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
Question:
Am I right in thinking that, When the Admin/Regular User is validated he/she must be redirected in this line in the code snippet above
return RedirectToAction("Index", "Home");
to the appropriate Index Action Method(Read: Index Action Method in the appropriate Area).
If so, I would like to know how.
I am confused because a constant string "Profile" is involved and it is not the usual stuff involving an action method and a controller name. "Profile" is neither a controller nor an action method.
Inspired by this post
MVC role-based routing
Instead of
return RedirectToAction("Index", "Home");
in the LogOn Action Method, I replaced it with
return Redirect("/Profile");
It worked !!!
However, what I don't understand is, when I click Log Off, it renders the Index page in the main Views folder. So I have to click LogOff again to be taken back to the LogOn page.

Resources