Account creation via Form authentication ASP.NET MVC page - c#

I'm working on an intranet, so far I have switched from Windows authentication to Form authentication and I'm able to connect / register etc.
But here's what I'm expected to do : Instead of being able to create and account through the usual forms route, I wish to link the list of employees (that has many parameters, such as Login, Password, Name etc.) and be able to create a new user when I create a new Employee.
Here is my Employee creation controller :
public ActionResult Create()
{
ViewBag.CompanyList = _service.ListCompany();
ViewBag.SupervisorList = _service.ListSupervisor();
return View();
}
//
// POST: /Employee/Create
[HttpPost]
public ActionResult Create([Bind(Exclude = "Id")] Employee objEmployee, FormCollection form)
{
ViewBag.CompanyList = _service.ListCompany();
ViewBag.SupervisorList = _service.ListSupervisor();
objEmployee.CreatedDate = System.DateTime.Now;
objEmployee.UpdatedDate = System.DateTime.Now;
objEmployee.CompanyId = int.Parse(form["CompanyId"]);
objEmployee.Supervisor = form["Supervisor"];
if (_service.Create(objEmployee))
return new RedirectResult(Url.Action("Index"));
else
{
if (!_service.Validate(objEmployee))
return View();
else
return new RedirectResult(Url.Action("Index", "Error", new { Message = "Error Create Employee", NextPage = CRAWebSiteMVC.Properties.Resources.Employee + #"/" + CRAWebSiteMVC.Properties.Resources.Create }));
}
}
And here's the usual way I create an account via the normal form auth. registering :
[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");
}
[...]
}
// If we got this far, something failed, redisplay form
return View(model);
}
How may I create an account via the Employee creation panel and basically replace the usual user list by the employee list?

Now Usually the context, is automatically declared as db <- in the controllers.
it is Declared as
private ApplicationDbContext db = new ApplicationDbContext();
But in this Case in my example it says. context so just Change context to db if ApplicationDbContext is declared.
The bottom is an Example of Creating a User class and an Employee class at the same time. So inserting a record to the User While having a reference to the Employee class. But I guess you get that by now.
Notice that, I didn't add an encryption to the password. Cause that is a whole new topic of question.
var userStore = new UserStore<ApplicationUser>(context);
var userManager = new UserManager<ApplicationUser>(userStore);
if (!context.Users.Any(t => t.UserName == "admin#Konek.com"))
{
var user = new ApplicationUser { UserName = "admin#Konek.com", Email = "admin#Konek.com" };
userManager.Create(user, "Password1!");
context.Roles.AddOrUpdate(r => r.Name, new IdentityRole { Name = "Admin" });
context.Roles.AddOrUpdate(r => r.Name, new IdentityRole { Name = "Receptionist" });
context.Roles.AddOrUpdate(r => r.Name, new IdentityRole { Name = "Security" });
context.SaveChanges();
userManager.AddToRole(user.Id, "Admin");
Employee admingEmployee = new Employee
{
Age=25,
Citizenship="Filipino",
CivilStatus=CivilStatus.Single,
DateOfBirth=DateTime.Now,
EmailAddress="admin#Konek.com",
FirstName="Admin",
Gender=Gender.Male,
HomeAddress="None",
LandLine="531-5555",
LastName="Administrator",
MiddleName="admin",
MobileNumber="09275225222",
Photo = "*******",
PlaceofBirth="*****",
Password = "********",
Role=Role.Admin
};
context.Employees.Add(admingEmployee);
context.SaveChanges();

Related

How to insert a value in Database when using MVC identity framework in AspNetUsers Table?

I want to insert a value in DB and I am using the Asp.Net Identity framework, in my Register method when a new user registers I also want to add a new Id which is client_id by default this id is not inserted by the identity framework?
if (User.IsInRole("Avanceon"))
{
var MaxCustomerId = db.AspNetUsers.Max(x => x.Customer_Id);
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = model.UserName, Email = model.Email };
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
// Assign Role to user Here
await this.UserManager.AddToRoleAsync(user.Id, model.RoleName);
// Ends Here
// await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
ViewBag.userCreated = user.UserName + " Created Successfully";
ViewBag.Name = new SelectList(context.Roles.ToList(), "Name", "Name");
MaxCustomerId = MaxCustomerId + 1;
// db.AspNetUsers.LastOrDefault().Customer_Id = MaxCustomerId;
db.SaveChanges();
return View();
//return RedirectToAction("Index", "Home");
}
AddErrors(result);
}
}
ViewBag.Name = new SelectList(context.Roles.ToList(), "Name", "Name");
return View(model);
You normally can't simply insert any data to AspNetUsers table. You'll need create a class and inherit it from IdentityUser and do the necessary changes in your class.
With code first you should create a class say ApplicationUser which inherits IdentityUser. And add the property there:
public class ApplicationUser : IdentityUser
{
[Required]
public string ClientID { get; set; }
}
And then target ApplicationUser (instead of IdentityUser) in your code:
var user = new ApplicationUser
{
UserName = model.UserName,
Email = model.Email,
ClientID = model.ClientID,
};
Make below changes as well:
In ConfigureServices method of Startup.cs
services.AddIdentity<ApplicationUser, IdentityRole>();
In AccountController,
private readonly UserManager<ApplicationUser> _userManager;
private readonly SignInManager<ApplicationUser> _signInManager;
Add migration for this change to take effect

ASP.NET MVC: Get user id of currently logged in user

I am new to ASP.NET MVC and am trying to create a web app.
The problem I have is that in the controller class I need to get the UserID of the current user, but I am very confused about how one would do that.
Also, it seems that the user is not authenticated after logging in, because if I use the [Authorize] annotation it throws an HTTP Error 401.0 - Unauthorized error.
This is my Authentication.cs class:
public static class Authentication
{
public static bool CreateNewTicket(User user, bool rememberMe)
{
try
{
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
1,
user.Email,
DateTime.Now,
DateTime.Now.AddDays(5),
rememberMe,
user.ID.ToString(),
FormsAuthentication.FormsCookiePath
);
string encryptedTicket = FormsAuthentication.Encrypt(ticket);
HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
cookie.HttpOnly = true;
if (!HttpContext.Current.Request.IsLocal)
cookie.Secure = true;
HttpContext.Current.Response.Cookies.Add(cookie);
return true;
}
catch
{
return false;
}
}
public static bool AuthUser(string Email, string Password)
{
using (var db = new AntContext())
{
string password = Password;
string email = Email;
string hashedPW = GetHash(password);
bool userValid = db.Users.Any(user => user.Email == email && user.Password == hashedPW);
if (userValid)
{
var actUser = db.Users.FirstOrDefault(u => u.Email == Email && u.Password == hashedPW);
if (!actUser.IsLocked)
{
if (CreateNewTicket(actUser, false))
{
return true;
}
else
{
return false;
}
}
else if (actUser.IsLocked)
{
}
}
return false;
}
}
The actual problem happens when I try to store data in a database.
[HttpPost]
public ActionResult Q_FirstPage(ViewModels.Q1_Answer_VM vm)
{
vm.Qst = new Models.Questionnaire();
vm.Qst.NumericAnswers = new List<Models.NumericAnswer>();
vm.Qst.TextAnswers = new List<Models.TextAnswer>();
vm.Qst.IsComplete = false;
vm.Qst.StartedOn = DateTime.Now;
vm.Qst.NumericAnswers.Add(vm.Breite);
vm.Qst.NumericAnswers.Add(vm.Tiefe);
vm.Qst.NumericAnswers.Add(vm.Hoehe);
vm.Qst.TextAnswers.Add(vm.Sonstiges);
//vm.qst.User_ID = 22; if I set the User ID manually, it works
db.Questionnaires.Add(vm.Qst);
db.SaveChanges();
return View();
}
The Viewmodel works fine and returns the data input, but the UserID is null. The data table "Questionnaire" uses the UserID as a foreign key, which makes it throw an error when it comes to the savedata() part because I guess it expects the correct UserID. So I guess I need to get the current UserID, pass it to the instantiated object which is then passed to the data context and then saved into the database.
Unfortunately, I find it very hard to find complete information about how user authentication works in ASP.NET.
If you need more information, please let me know.
This is my Login method:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Login(Login_VM login_vm)
{
if (!ModelState.IsValid)
{
return View(login_vm);
}
if (Authentication.AuthUser(login_vm.Email, login_vm.Password) == true && (login_vm.Email != null || login_vm.Password != null))
{
Classes.Authentication.CreateNewTicket(login_vm.usr, true);
return RedirectToAction("Login");
}
else
return View("~/Views/Home/Index.cshtml");
}
And this is my registration method:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult AddUser(User model)
// add new User to db
{
if (ModelState.IsValid)
{
User usr = new Models.User();
usr = model;
model.Password = Authentication.GetHash(model.Password);
db.Users.Add(model);
db.SaveChanges();
}
return View();
}
Solved the problem by following this link: howto get the user id from a FormsAuthentication page in asp.net MVC? posted by https://stackoverflow.com/users/2516718/derloopkat
The System.Web.HttpContext.Current.User.Identity.Name Function returns the "name" attribute in the Authentication Ticket, which in my case was the email address. I then got the User ID by having a query to the Users database.
db.Users.Where(x => x.Email == System.Web.HttpContext.Current.User.Identity.Name).FirstOrDefault().ID;
Thanks for everybody's help.
Update in 2020: The query can be simplified to:
db.Users.FirstOrDefault(x => x.Email == System.Web.HttpContext.Current.User.Identity.Name).ID;
There are two simple ways to get current user in MVC 5.
If you are inside the controller class,the current user can be fetched as follows,
string userId = User.Identity.GetUserId();
Do not forget to add namespace:
using Microsoft.AspNet.Identity;
Other scenario could be that you are not inside the controller class and want to fetch the user information. You can fetch that using HttpContext class.
HttpContext.Current.User.Identity.GetUserId();

Registering and update model in a single API call

I have an ASP.net API 2 application with a register method, which basically does the following:
var user = new ApplicationUser() { UserName = user.email, Email = user.email };
UserManager.AddToRole(user.Id, "SomeRole");
In the same controller, I would like to assign a model class to the application user, for example:
var parent = db.Parents.Find(parentToCreate.id);
db.SaveChanges();
This gives me an error that the user name is already taken. I know that the issue is relating to there being two model trackers, one for the UserManager.CreateAsync and one for updating the db. Will it be alright to create users without using CreateAsync or is there another way to avoid this error?
Note that I think that this could be achieved by putting a Parent property on the account property, but not all accounts are parents, so I do not want to do this solution. A parent has an account, so there is an account property on the parent.
As requested, the full register method is as follows:
[AllowAnonymous]
[Route("RegisterParent")]
public async Task<IHttpActionResult>RegisterParent(ParentRegisterBindingModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var user = new ApplicationUser() { UserName = model.email, Email = model.email };
Parent parentToCreate = new Parent();
db.Parents.Add(parentToCreate);
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.SaveChanges();
try
{
IdentityResult result = await UserManager.CreateAsync(user, model.password);
// The following two lines give an error
parentToCreate.account = user;
// the above two lines give an error
UserManager.AddToRole(user.Id, "ParentRole");
db.SaveChanges();
}
catch (Exception e)
{
Console.Write(e);
// e returns here with message
}
return Ok(200);
}
This is a simplified example based on minimal example provided in OP.
Based on conversation to clarify current design the Parent model would need to be updated to have a proper code first Foreign Key relationship
public class Parent {
//...other properties
//Foreign key
public string accountid { get; set; }
//navigation property
[ForeignKey("accountid")]
public ApplicationUser account { get; set; }
}
With that then you only need to assign the user id when creating the parent.
Refactoring/abstracting out specific responsibilities.
public interface IParentService {
Task AddParentAsync(ApplicationUser user);
}
public class ParentService : IParentService {
ApplicationDbContext db;
public ParentService(ApplicationDbContext db) {
this.db = db;
}
public async Task AddParentAsync(ApplicationUser user) {
Parent parentToCreate = new Parent() {
//...set other properties
accountid = user.Id
};
db.Parents.Add(parentToCreate);
await db.SaveChangesAsync();
}
}
Next separating the action into distinct processes to avoid concurrency issues.
public class AccountController : ApiController {
ApplicationUserManager userManager;
IParentService parentService;
public AccountController(ApplicationUserManager userManager, IParentService parentService) {
this.userManager = userManager;
this.parentService = parentService;
}
[AllowAnonymous]
[Route("RegisterParent")]
public async Task<IHttpActionResult> RegisterParent(ParentRegisterBindingModel model) {
if (!ModelState.IsValid) {
return BadRequest(ModelState);
}
var user = new ApplicationUser() { UserName = model.email, Email = model.email };
var result = await userManager.CreateAsync(user, model.password);
if (result.Succeed) {
try {
await userManager.AddToRole(user.Id, "ParentRole");
await parentService.AddParentAsync(user);
return Ok();
} catch (Exception e) {
userManager.Delete(user.Id);
Console.Write(e);
// e returns here with message
return BadRequest(); //OR InternalServerError();
}
} else {
foreach (var error in result.Errors) {
ModelState.AddModelError("", error);
}
return BadRequest(ModelState);
}
}
}
You would obviously register dependencies with the DI framework to allow for proper injection.

Im trying to create User Roles in MVC5. My context property is showing null i have no idea why

https://gyazo.com/0e64a4a003c33f117f114b914ccde492
As you can see in the picture above when i call the RegisterRole Action i got a Nullreference error. It's my first time working with ApplicationDbContext class.
Controller class:
private ApplicationDbContext context;
Action Methods:
[HttpGet]
public ActionResult RegisterRole()
{
ViewBag.Name = new SelectList(context.Roles.ToList(), "Name", "Name");
ViewBag.UserName = new SelectList(context.Users.ToList(), "UserName", "UserName");
return View();
}
[ValidateAntiForgeryToken]
[HttpPost]
public async Task<ActionResult> RegisterRole(RegisterViewModel model, ApplicationUser user)
{
var userId = context.Users.Where(i => i.UserName == user.UserName).Select(s => s.Id);
string updatedId = "";
foreach (var i in userId)
{
updatedId = i.ToString();
}
await this.UserManager.AddToRoleAsync(updatedId, model.Name);
return RedirectToAction("Index", "Home");
}
If context was not initialized, then it should be null.
You can inject it with controller construct method, or simply initialized with context = new ApplicationDbContext(connectionString);
connectionString could be settings in config file.

How to add roles from database

I have my ASP.NET MVC 4 project and database (SQL Server 2008)
And I've created an entity framework model, with auto-generated models.
And in the database there is a table called Roles (2 fields, Id and name)
There are 3 roles: admin, moderator, user.
Plus Account controller:
public class AccountController : Controller
{
private korovin_idzEntities db = new korovin_idzEntities();
//
// GET: /Account/LogOn
public ActionResult LogOn()
{
return View();
}
//
// POST: /Account/LogOn
[HttpPost]
public ActionResult LogOn(LogOnModel model/*, string returnUrl*/)
{
if (ModelState.IsValid)
{
var user = db.Users.Where(x => x.username == model.UserName && x.password == model.Password).FirstOrDefault();
if (user != null)
{
user.isRemember = model.RememberMe;
db.SaveChanges();
ViewBag.UserName = model.UserName;
FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
FormsAuthentication.RedirectFromLoginPage(model.UserName, false);
}
else
{
ModelState.AddModelError("", "The user name or password provided is incorrect.");
}
}
return View(model);
}
}
Where and how can i initialize roles in my asp.net mvc application? I've tried to check whether role exists and to initialize role by rolemanager in account controller, but i think it's not a good solution.
Is it possible to initialize roles in global.asax.cs?
I know that I should attach roles to user in log on function.
Thanks in advance :)
Here is my solution, I thought that there is some kind of a structure for storing a names of roles and there is needed to initialize this structure, but i was wrong, and after googling, I've found the solution:
protected void Application_PostAuthenticateRequest(object sender, EventArgs e)
{
var context = HttpContext.Current;
if (context.Request.IsAuthenticated)
{
string[] roles = LookupRolesForUser(context.User.Identity.Name);
var newUser = new GenericPrincipal(context.User.Identity, roles);
context.User = Thread.CurrentPrincipal = newUser;
}
}
#region helper
private string[] LookupRolesForUser(string userName)
{
string[] roles = new string[1];
CosmosMusic.Models.korovin_idzEntities db = new CosmosMusic.Models.korovin_idzEntities();
var roleId = db.Users.Where(x => x.username == userName).FirstOrDefault().id_role;
roles[0] = db.Role.Where(y => y.id_role == roleId).FirstOrDefault().name;
return roles;
}
#endregion

Categories

Resources