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? - asp.net-web-api

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)

Related

Pass complex object between action methods ASP.Net MVC Core

I studied most of the similar questions but couldn't find the answer!
Let me declare that I can define a simple TempData like an string,int and get it in another action method successfully, but
I have 3 parameters/variable in ActionMethod1 which is named "ExternalLoginCallBack", and need to ask a "UserName" from user on client side and then save the total 4 parameters in ActionMethod2 which is named "CreateExternalUser".
This is what I have.
AskUserNameView_NoActionMethod.cshtml as below:
#model ExternalUserViewModel
<form asp-action="CreateExternalUser" asp-controller="Account" method="post">
<label asp-for="UserName">Input your UserName Here: </label>
<input asp-for="UserName" >
<input type="submit" value="ُSubmit"/>
</form>
(Using TempData) Attemp-No.1:
public async Task<IActionResult> ActionMethod1
//some codes here
var externalLoginInfo = await _signInManager.GetExternalLoginInfoAsync();
TempData["externalLoginInfo"] = externalLoginInfo;
TempData["email"] = email;
TempData["returnUrl"] = returnUrl;
return View("AskUserNameView_NoActionMethod");
but instead of showing the AskUserNameView_NoActionMethod.cshtml it shows just a white page with no errors,no exception and nothing :
Attemp-No2: I removed "ExternalLoginInfo" type and only two simple string as an object remained to pass to ActionMethod2:
public async Task<IActionResult> ActionMethod1
//some codes here
var externalUserViewModel= new ExternalUserViewModel()
{
Email = email,
ReturnUrl = returnUrl,
};
TempData["externalUserViewModel"] = externalUserViewModel;
return View("AskUserNameView_NoActionMethod");
but again the white page above appeared. When I remove the complex TempData, my AskUserNameView_NoActionMethod.cshtml rendered successfully, and I can pass UserName which is entered by client side, to ActionMethod2. But without 3 other parameters which is needed to create a new External user !!
My ExternalUserViewModel is as below:
public class ExternalUserViewModel
{
public ExternalLoginInfo ExternalLoginInfo { get; set; }
public string Email { get; set; }
public string UserName { get; set; }
public string ReturnUrl { get; set; }
}
and already added these codes to startup.cs:
services.AddControllersWithViews();
services.AddSingleton<ITempDataProvider, CookieTempDataProvider>();
app.UseSession();
If TempData is not apllicable, I tried to pass my model with 3 parameters (Email,ReturnUrl,ExternalLoginInfo ) to strongly typed AskUserNameView_NoActionMethod.cshtml, but again Username entered by client side,Email and returnedUrl passed to ActionMethod2 but externalLoginInfo was null .
Summary: need an example to pass a complex data/object from actionmethod1 to actionmethod2 , without redirect to actionmethod2 !!
You have two methods to achieve it.
As the TempData cannot store complex object here ,you can Serialize the object to json string and store it in TempData, then you can get the json string in CreateExternalUser action and Deserialize this json string to the correspond object as follow:
public async Task<IActionResult> ActionMethod1()
{
//some codes here
var externalLoginInfo = await _signInManager.GetExternalLoginInfoAsync();
TempData["externalLoginInfo"] = JsonConvert.SerializeObject(externalLoginInfo);
TempData["email"] = email;
TempData["returnUrl"] = returnUrl;
return View("AskUserNameView_NoActionMethod");
}
Receive:
public async Task<IActionResult> CreateExternalUser(UserName userName)
{
//some codes here
var externalLoginInfo = JsonConvert.DeserializeObject<ExternalLoginInfo>(TempData["externalLoginInfo"].ToString());
var email = TempData["email"] as string;
var returnUrl = TempData["returnUrl"] as string;
return View();
}
Another method is to create a custom method named TempDataExtensions to pass object from an action to another.
public static class TempDataExtensions
{
public static void Put<T>(this ITempDataDictionary tempData, string key, T value) where T : class
{
tempData[key] = JsonConvert.SerializeObject(value);
}
public static T Get<T>(this ITempDataDictionary tempData, string key) where T : class
{
object o;
tempData.TryGetValue(key, out o);
return o == null ? null : JsonConvert.DeserializeObject<T>((string)o);
}
}
Store object:
var externalLoginInfo = await _signInManager.GetExternalLoginInfoAsync();
TempData.Put("externalLoginInfo", externalLoginInfo);
Get object:
var externalLoginInfo = TempData.Get<ExternalLoginInfo>("externalLoginInfo");

Correct Implementation of Forgot Password AspNetBoilerPlate

Im using aspnetboilerplate (MVC) and wanted to implement a forgot password feature to allow the user to reset their own passwords using a link on the login screen.
I imagine this to work by generating a password reset code which is then emailed to the user.The user follows the link and is taken to a screen allowing them to reset the password.
Im stuck at the initial stage. i started with a copy of the login action after noticing that when attempting to log in the user object was returned. From here i attempt to set a password reset code.
[HttpPost]
[UnitOfWork]
public virtual async Task<JsonResult> ForgotPassword(ForgotPasswordViewModel forgotPasswordModel, string returnUrl = "", string returnUrlHash = "")
{
returnUrl = NormalizeReturnUrl(returnUrl);
if (!string.IsNullOrWhiteSpace(returnUrlHash))
{
returnUrl = returnUrl + returnUrlHash;
}
var loginResult = await _logInManager.LoginAsync(forgotPasswordModel.UsernameOrEmailAddress, "ForgotPassword", GetTenancyNameOrNull());
loginResult.User.SetNewPasswordResetCode();
switch (loginResult.Result)
{
case AbpLoginResultType.Success:
return Json(loginResult);
default:
throw _abpLoginResultTypeHelper.CreateExceptionForFailedLoginAttempt(loginResult.Result, forgotPasswordModel.UsernameOrEmailAddress, GetTenancyNameOrNull());
}
}
Checking the AbpUser table after the
loginResult.User.SetNewPasswordResetCode();
i cannot see any password reset code for the user, they are all null.
Could someone point me in the right direction.
Thanks in advance
Thanks to answer below for being correct, just for completion below is exactly what worked. Obviously ignore the json return at the end
public virtual async Task<JsonResult> ForgotPassword(ForgotPasswordViewModel forgotPasswordModel, string returnUrl = "", string returnUrlHash = "")
{
//var user = await GetUserByChecking(emailAddress);
var user = await _userManager.FindByEmailAsync(forgotPasswordModel.UsernameOrEmailAddress);
if (user == null)
{
throw new UserFriendlyException("User not found!");
}
user.SetNewPasswordResetCode();
//Send an email to user with the below password reset code
/* Uri.EscapeDataString(user.PasswordResetCode) */
return Json("");
}
public class AccountAppService: IAccountAppService
{
public UserManager UserManager {get; set; }
public async Task SendPasswordResetCode(string emailAddress)
{
var user = await UserManager.FindByEmailAsync(emailAddress);
if (user == null)
{
throw new UserFriendlyException("User not found!");
}
user.SetNewPasswordResetCode();
//Send an email to user with the below password reset code
/* Uri.EscapeDataString(user.PasswordResetCode) */
}
}

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.

How to get user context during Web Api calls?

I have an web front end calling an ASP Web Api 2 backend. Authentication is managed with ASP Identity. For some of the controllers I'm creating I need to know the user making the call. I don't want to have to create some weird model to pass in including the user's identity (which I don't even store in the client).
All calls to the API are authorized using a bearer token, my thought is the controller should be able to determine the user context based on this but I do not know how to implement. I have searched but I don't know what I'm searching for exactly and haven't found anything relevant. I'm going for something like...
public async Task<IHttpActionResult> Post(ApplicationIdentity identity, WalkthroughModel data)
Update
I found the below which looked very promising... but the value is always null! My controller inherits from ApiController and has an Authorize header.
var userid = User.Identity.GetUserId();
Update 2
I have also tried all of the solutions in Get the current user, within an ApiController action, without passing the userID as a parameter but none work. No matter what I am getting an Identity that is valid and auth'd, but has a null UserID
Update 3
Here's where I'm at now.
[Authorize]
[Route("Email")]
public async Task<IHttpActionResult> Get()
{
var testa = User.Identity.GetType();
var testb = User.Identity.GetUserId();
var testc = User.Identity.AuthenticationType;
var testd = User.Identity.IsAuthenticated;
return Ok();
}
testa = Name: ClaimsIdentity,
testb = null,
testc = Bearer,
testd = true
The user is obviously authenticated but I am unable to retrieve their userID.
Update 4
I found an answer, but I'm really unhappy with it...
ClaimsIdentity identity = (ClaimsIdentity)User.Identity;
string username = identity.Claims.First().Value;
That gets me the username without any db calls but it seems very janky and a pain to support in the future. Would love if anyone had a better answer.
What if I need to change what claims are issued down the road? Plus any time I actually need the user's id I have to make a db call to convert username to ID
A common approach is to create a base class for your ApiControllers and take advantage of the ApplicationUserManager to retrieve the information you need. With this approach, you can keep the logic for accessing the user's information in one location and reuse it across your controllers.
public class BaseApiController : ApiController
{
private ApplicationUser _member;
public ApplicationUserManager UserManager
{
get { return HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>(); }
}
public string UserIdentityId
{
get
{
var user = UserManager.FindByName(User.Identity.Name);
return user.Id;
}
}
public ApplicationUser UserRecord
{
get
{
if (_member != null)
{
return _member ;
}
_member = UserManager.FindByEmail(Thread.CurrentPrincipal.Identity.Name);
return _member ;
}
set { _member = value; }
}
}
I use a custom user authentication (I dont use AspIdentity because my existing user table fields was far different from IdentityUser properties) and create ClaimsIdentity passing my table UserID and UserName to validate my bearer token on API calls.
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
User user;
try
{
var scope = Autofac.Integration.Owin.OwinContextExtensions.GetAutofacLifetimeScope(context.OwinContext);
_service = scope.Resolve<IUserService>();
user = await _service.FindUserAsync(context.UserName);
if (user?.HashedPassword != Helpers.CustomPasswordHasher.GetHashedPassword(context.Password, user?.Salt))
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
}
catch (Exception ex)
{
context.SetError("invalid_grant", ex.Message);
return;
}
var properties = new Dictionary<string, string>()
{
{ ClaimTypes.NameIdentifier, user.UserID.ToString() },
{ ClaimTypes.Name, context.UserName }
};
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
properties.ToList().ForEach(c => identity.AddClaim(new Claim(c.Key, c.Value)));
var ticket = new AuthenticationTicket(identity, new AuthenticationProperties(properties));
context.Validated(ticket);
context.Request.Context.Authentication.SignIn(identity);
}
And how I use the ClaimsIdentity to retrieve my User table details on User ApiController Details call.
[HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
[Route("Details")]
public async Task<IHttpActionResult> Details()
{
var user = await _service.GetAsync(RequestContext.Principal.Identity.GetUserId<int>());
var basicDetails = Mapper.Map<User, BasicUserModel>(user);
return Ok(basicDetails);
}
Notice the
ClaimTypes.NameIdentifier = GetUserId() and ClaimTypes.Name = GetUserName()

MVC3 Edit customer with username

I am trying to edit customer with username which is using User.Identity.Name.
I don't know how to write Where condition in controller.
It looks easy. Could you help me? thanks.
Here is my coding.
[Authorize]
public ActionResult Edit()
{
//the username gets username through User.Identity.Name.
string username = User.Identity.Name;
//How can I write below coding?
//In DB, it has userName field.
Customer customer = db.Customer.Where(userName = username);
return View(customer);
}
[HttpPost]
public ActionResult Edit(Customer customer)
{
if (ModelState.IsValid)
{
db.Entry(customer).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(customer);
}
You need to learn how lambda expressions work:
.Where(c => c.UserName == username)
c is the implicitly-typed parameter.
Also, if you want a single result, you should call FirstOrDefault() instead; Where() returns a sequence.
Customer customer = db.Customer.Single(c=>c.UserName == username)
throws exception if returns one than more matching element
or
Customer customer = db.Customer.SingleOrDefault(c=>c.UserName == username);
returns null if returns more than one matching element

Resources