Redirect after Register Using UserID - asp.net-mvc

using VS'12 asp.net MVC4 C# InternetApplication with KendoUI and Simplemembership EF Code first.
this is what VS gives you to start out with.
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
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("Index", "Home");
.
.
.
Here is where i would like it to RedirectToAction to my Controller ChangeUsersInfoController, and send it the id of the newly created user.
To get the ID i have tried
1.
var UserID = (from u in db.UserProfiles
where u.UserName == User.Identity.Name
select new
{
UserID = u.UserID
}).Single();
2.
var userID = System.Web.Security.Membership.GetUser().ProviderUserKey;
return RedirectToAction("Edit","ChangeUsersInfo", userID);
I have also Tried return RedirectToAction("Edit","ChangeUsersInfo"); to see if it would let me jsut send it there without a variable.
For some reason
variable returned = Null
variable returned = Null
doesnt work because 1 and 2 didnt
seems to not redirect to the new EDIT but to the LOG IN Screen
What is the reason behind my nulls and the fail Redirect?
Yes the database has users

var userID = System.Web.Security.Membership.GetUser().ProviderUserKey;
Using the WebSecurity and System.Web.Security items will only work on subsequent request because you have not sent the auth cookie back to the client yet (this is where it pulls its data from). Given that, you should not even have to send the user Id of the user in the redirect URL...they are logged in and you can just get it at the controller/action that you are going to. By grabbing the userId from the auth ticket, you now do not have to check if the user Id passed in the URL is actually the user that is currently logged in.
Example:
Login Method
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Register(RegisterModel model)
{
if (!ModelState.IsValid)
{
//send em back with the errors
Return View();
}
try
{
WebSecurity.CreateUserAndAccount(model.UserName, model.Password);
WebSecurity.Login(model.UserName, model.Password);
return RedirectToAction("Index", "ChangeUsersInfo");
}...
}
Change User Info Controller
[Authorize]
public ActionResult Index()
{
var userId = WebSecurity.CurrentUserId;
var model = GetUserInfoService.GetUserInfo(userId);
Return View(model);
}

Related

Asp.Net MVC Identity Reset Password

Reset Password by Admin - Without Email Link Only Admin can Reset Password, I get this code from MVC Admin reset of User Password but in my project, I get an error on the line
await store.SetPasswordHashAsync(cUser, hashedNewPassword);
Code:
//
// POST: /Account/ResetPassword
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> ResetPassword(ResetPasswordViewModel model)
{
ApplicationDbContext context = new ApplicationDbContext();
UserStore<ApplicationUser> store = new UserStore<ApplicationUser>(context);
UserManager<ApplicationUser> UserManager = new UserManager<ApplicationUser> (store);
string userId = model.Id;
string newPassword = model.NewPassword;
string hashedNewPassword = UserManager.PasswordHasher.HashPassword(newPassword);
ApplicationUser cUser = await store.FindByIdAsync(userId);
await store.SetPasswordHashAsync(cUser, hashedNewPassword);
await store.UpdateAsync(cUser);
return RedirectToAction("Index");
}
enter image description here
View code of reset pass word
EDIT: after seeing the view, the thing you can do is check if the view is actually getting an ID. Check the controller for the [get] action if it gives an id, one thing I do to check that is to temporarily change:
#Html.HiddenFor()
to
#Html.TextBoxFor()
then do a refresh.
You can also check the value of id in the breakpoint window if you are on debugging mode

What's the best way to direct user to different views by roles?

In my ASP.NET MVC 5 application, we have a bunch of user roles, such as Admin, ReportUser, ProjectManager and stuffs like these. I want the application to redirect the user to views immediately after login according to the following rules:
If user is Admin, redirect to /Admin/Index
If user is ReportUser, redirect to /Report/Index
If user is ProjectManager, redirect to /Project/Index
I've already set up a role manager using AspNetWindowsTokenRoleProvider in web.config, and I am setting user roles in MyMvcApplication_PostAuthenticateRequest of global.asax, which works well.
But, I am not clear where and what is the best way to do the redirect. In OnAuthorization method of a custom authorize attribute class? Or in MyMvcApplication_PostAuthenticateRequest method of global.asax?
If you're using the default Asp.net Identity Login and template logic you should have a login method that looks something like:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
if (ModelState.IsValid)
{
var user = await _userManager.FindAsync(model.Email, model.Password);
if (user != null)
{
await SignInAsync(user, model.RememberMe);
return RedirectToLocal(returnUrl);
}
else
{
ModelState.AddModelError("", "Invalid username or password.");
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
So create a new method:
public async Task<ActionResult> GoHome()
{
if (this.User.IsInRole("Admin"))
{
return Redirect("Action", "Controller");
}
// etc etc
}
Then just update the Login method by changing:
return RedirectToLocal(returnUrl);
to
return Redirect("GoHome");
The reason for the double redirect is that authentication takes place before the MVC pipeline, which means that await SignInAsync(user, model.RememberMe) will not change the current user context, it requires a redirect for MVC to see the change. Thus on the next page, it can read the roles and redirect correctly.

System.Web.Mvc.HttpAntiForgeryException: MVC 5

Using MVC 5.1.1/VS 2013 Professional/.Net 4.5
I keep getting error once in a while (from localhost and from production IIS 7):
System.Web.Mvc.HttpAntiForgeryException: The anti-forgery cookie token and form field token do not match.
The issue seems to be when i logout a user, sometimes when i go to authenticate again thats when i get the error.
My authentication code looks like something like this:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginViewModel model)
{
if (ModelState.IsValid)
{
var user = _uow.UserRepository.FindLogin(model.Email, model.Password);
if (user != null)
{
var claims = new List<Claim>();
claims.Add(new Claim(ClaimTypes.Email, user.Email));
claims.Add(new Claim(ClaimTypes.NameIdentifier, user.UserID.ToString()));
claims.Add(new Claim(ClaimTypes.Role, user.UserLevel.ToString()));
var id = new ClaimsIdentity(claims, DefaultAuthenticationTypes.ApplicationCookie);
var ctx = Request.GetOwinContext();
var authenticationManager = ctx.Authentication;
authenticationManager.SignIn(new AuthenticationProperties { IsPersistent = true }, id);
}
else
{
ModelState.AddModelError("", "Invalid Email Address or Password.");
}
}
return View(model);
}
Update with LogOut Method:
[HttpGet]
[AllowAnonymous]
public ActionResult LogOut(LoginViewModel model)
{
Session.Abandon();
return SignOffUser();
}
private ActionResult SignOffUser()
{
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
return RedirectToAction("Index", "Home");
}
LogOut Form View
#if (Request.IsAuthenticated)
{
using (Html.BeginForm(null, null, FormMethod.Post, new {id = "logoutForm", #class = "navbar-right"}))
{
#Html.AntiForgeryToken()
....
}
}
Another thing you may want to look at is that on your logout page, you don't necessary validate the forgery token.
Try changing this:
[HttpGet]
[AllowAnonymous]
public ActionResult LogOut(LoginViewModel model)
{
To this
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult LogOut(LoginViewModel model)
{
My bet is that the token is changing on the page, and since it's not validated, ASP.NET doesn't know if it is truly correct or not.
E: just noticed, it should actually be an httppost on logout
Show your logout form(view).
This happens if you are calling the logout method in your controller from your view but don't have antiforgerytoken generated inside the form.
Your form should look like
#using(Html.BeginForm("Action","Controller"))
{
#Html.antiforgerytoken()
....
}
Then the action you call via your view should look like
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult MyAction()
{
return content("hello user! Antiforgerytoken has been validated1");
}
PS: No matter what action method your form calls, if you want to have antiforgery token that needs to be validated, then the form and action method should look like what I've mentioned above.
Try setting explicitly machine key in web.config (under system.web):
<machineKey validationKey="971E32D270A381E2B5954ECB4762CE401D0DF1608CAC303D527FA3DB5D70FA77667B8CF3153CE1F17C3FAF7839733A77E44000B3D8229E6E58D0C954AC2E796B" decryptionKey="1D5375942DA2B2C949798F272D3026421DDBD231757CA12C794E68E9F8CECA71" validation="SHA1" decryption="AES" />
Here's a site that generate unique Machnie Keys http://www.developerfusion.com/tools/generatemachinekey/
link: The anti-forgery cookie token and form field token do not match in MVC 4

How to set session variable when user logs in with 'Remember Me' cookie in asp mvc

Based on the default Identity framework, I'd like to set a session variable when the user logs in to the application.
This works well:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
if(ModelState.IsValid)
{
// Validate the password
IdentityResult result = await IdentityManager.Authentication.CheckPasswordAndSignInAsync(AuthenticationManager, model.UserName, model.Password, model.RememberMe);
if(result.Success)
{
//save display name in session view
SiteUser user = await _siteDbContext.Users.SingleOrDefaultAsync(u => u.UserName == model.UserName);
Session["displayName"] = user.DisplayName;
return RedirectToLocal(returnUrl);
}
AddErrors(result);
}
// If we got this far, something failed, redisplay form
return View(model);
}
Which gets displayed in the site's top bar with this line:
#Html.ActionLink(Session["displayName"].ToString(), "Manage", "Account", null)
However, when the I log in with the 'Remember Me' option checked, close the browser and start it again, the session variable doesn't get set, and the page throws a null reference exception.
Digging around a little, it appears as if the /Account/Login action is set as the default login path, but it never gets called with the cookie authentication.
How can I get in the middle - or right after - of the authentication process and set my session variable?

How do you create roles in Microsoft.Owin.Security in VisualStudio 2013 RC AccountController.cs - API documentation

In VisualStudio 2013 RC, using MVC5, in AccountController.cs, I had to modify the Login method to call WebSecurity.Login as I'm still using WebSecurity and Webmatrix to add users and user roles. I populate users and roles with WebSecurity and Webmatrix API using an Entity Framework 6 seed method. In my code examples WebSecurity.Login will handle a local user account, and CheckPasswordAndSignInAsync will handle a Google account login.
Should OWIN be a replacement for Webmatrix and the Websecurity API, if so what is Microsoft's OWIN API to create roles and users? Can't seem to find much documentation on OWIN in MSDN. Has anyone created any sample code or aware of any docs that explain
how to use Microsofts' flavor of OWIN? Do you have to write your own code to populate
roles and users to the OWIN generated tables such as AspNetUsers and AspNetUserRoles?
This is login method:
public async Task Login(LoginViewModel model, string returnUrl)
{
if (ModelState.IsValid)
{
// Validate the password
IdentityResult result = await IdentityManager.Authentication.CheckPasswordAndSignInAsync(AuthenticationManager, model.UserName, model.Password, model.RememberMe);
if (result.Success)
{
return RedirectToLocal(returnUrl);
}
//added this for roles to work
else if (ModelState.IsValid && WebSecurity.Login(model.UserName, model.Password, persistCookie: model.RememberMe))
{
return RedirectToLocal(returnUrl);
}
else
{
AddErrors(result);
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
This is signout method:
// POST: /Account/LogOff
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult LogOff()
{
AuthenticationManager.SignOut();
WebSecurity.Logout();
return RedirectToAction("Index", "Home");
}
In order to create a user, you need to write code like this:
UserManager<ApplicationUser> userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
var user = new ApplicationUser() { UserName = model.UserName };
// Add the Admin role to the user.
user.Roles.Add(new IdentityUserRole() { Role = new IdentityRole("Admin") });
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
// Code after successfully creating the user.
}

Resources