I need "admin approval" for login as user after the registration. I am doing it in asp.net MVC, using ms sql, visual studio. I am new to it,need help badly, how many way I can do it and whats the process to do that.
My thought: I made login Registration with email verify. Now I need to make admin verify.
Here is my database table :
Database: I made a registration table(Tbl_User), Approval Table(Tbl_Approval). I need to confirm admin approval while login:
var approval = dc.Tbl_Approval.Where(m => m.Tbl_User.EmailID == login.EmailID).FirstOrDefault();
if (!approval.ApprovalStatus)
{
ViewBag.Message = "Please wait for admin approval";
return View();
}
For this I need to insert the Tbl_User data into Tbl_Approval table which is previously empty. so I need the query in the controller action(for Tbl_Approval) to get the (Tbl_User)list into Tbl_Approval table and edit the Approval status. I tried this:-
public ActionResult List()
{
List<Tbl_User> userList = db.Tbl_User.ToList();
Tbl_Approval approval = new Tbl_Approval();
List<Tbl_Approval> approvalUserList = userList.Select(x => new Tbl_Approval { UserID = x.UserID }).ToList();
return View(approvalUserList);
}
Please help me on the controller action to get the(Tbl_User) list into the Tbl_Approval table. Also suggest me any other good way to do this task.
You can create the Action method for approval process. When admin approves any particular user, you need to pass that userId. I have used EntityFramework for the example.
Here is the code that should work
public ActionResult ApproveUser(int userId)
{
var user = context.Users.Find(userId);
if(user != null)
{
user.ApproveStatus = 1;
context.Entry(user).State = System.Data.Entity.EntityState.Modified;
context.SaveChanges();
}
return View();
}
TO solve this issue do the following i.e.
Add the status column in your login table and set the default approval status for all new sign ups as not approved.
Create a module for admin only in your web portal to view/approve the new sign ups.
Create designated actions with view pages in your new module to view and approve the signups.
I recommend creating a new controller for this new module that is accessible to the admin only and not to everyone else.
When the admin login the system show notifications to him so, he can open and go to this new module and perform approval actions.
When the admin performs the approval action update the approval status from not approve to approve.
Related
I am currently developing a Web Application with ASP.NET MVC 5 with Visual Studio 2019.
The App is about a school management system.
App has a Control and Management System, which is having same UI for all logged in users with some roles.
Roles are Administrator, Teacher, Accountant
When logged in by any of the user of above Roles, user is presented with a Home Screen Dashboard, where they can view School related and class related brief snapshot data.
An Administrator will be able to see all the data of school and students and teachers on the same dashboard page and all over the web app.
A Teacher will be able to see data related to their class and students only, not the data of Administrator and Accountant Roles.
I thought of using passing a parameter to each LINQ query with some id of logged in user, but what happens is, where in LINQ is beneficial only when Teacher is logged in but Administrator needs all data so I need to modify the query that time.
How to achieve this with same controller, giving full data to Administrator role and giving partial data to Teacher Role?
HomeController
public class HomeController : Controller
{
DBEntities db = new DBEntities();
public ActionResult Index()
{
return View();
}
public ActionResult GetLatestActivity(int id)
{
var data = from n in db.ACTIVITies
where n.USERID == id //This is ok when teacher is logged in but Admin needs all data, so not useful there
orderby n.ID descending
select new ActivityViewModel
{
ID = n.ID,
AREA = n.AREA,
SECTION = n.SECTION,
MESSAGE = n.MESSAGE,
CREATE_TIMESTAMP = (DateTime)n.CREATE_TIMESTAMP
};
return Json(data.Take(6), JsonRequestBehavior.AllowGet);
}
}
I think you can do something like this if you are using Microsoft.AspNet.Identity, because it's not clear to me. Otherwise you can implement your own isAdmin check method.
public ActionResult GetLatestActivity(int id)
{
var isAdmin = User.IsInRole("Administrator");
var data = from n in db.ACTIVITies
where n.USERID == (isAdmin ? n.USERID : id)
orderby n.ID descending
select new ActivityViewModel
{
ID = n.ID,
AREA = n.AREA,
SECTION = n.SECTION,
MESSAGE = n.MESSAGE,
CREATE_TIMESTAMP = (DateTime)n.CREATE_TIMESTAMP
};
return Json(data.Take(6), JsonRequestBehavior.AllowGet);
}
Edit: I am still encountering this issue but I have solved it displaying the applications on 2 users profile instead of the user that created it. I am still running into the issue of redirecting to the wrong ID however and I can't find any information online about it. All the breakpoints up to the redirect point to the correct ID so I am really perplexed. As stated below, I had altered my viewbag and variables to be consistent and it did not fix the issue.
I have an application that allows users to add applications to their profile. Their profile will list all of the applications made by that user. The application has been configured in the RouteConfig file to initialise the application in the profile of UserId 1.
What is happening is that if I create an application for UserId 1, it works fine, adds the application to the list of applications for UserId 1 and displays it. If I create a new user (UserId 2) and then proceed to add a new application for that user, the redirect action that happens when the application is submitted to the database takes me back to UserId 1's page with the application being added to UserId 1's list and also to the UserId that created it (In this instance, UserId 2). I'm not sure why this is happening as I am explicitly telling it to get the UserId from the ViewBag that is storing the correct UserId.
If I look into the database, there is only 1 record for the application. I can delete the application in UserId 1's list and it will still exist in UserId 2's list and also the database. If I remove it through the UserId 2's page, it will remove the record from all lists and database. This also applies to updating the details of the application.
When I've set a breakpoint at the very end where the controller will pick up the UserId and then redirect me to that UserId's page. It states the correct UserId's page it needs to redirect to (In the scenario above, it states the UserId is 2). However, as already stated, it is redirecting me to the UserId 1.
If I remove the route in the RouteConfig file that initialises the application in UserId 1 and just load up the default index page, create a user then create an application, I am given an error stating System.NullReferenceException because I'm trying to display the name of the user using - <h2>User Profile for #Model.Name</h2> so it's not picking up the details of the UserId. I'm not sure why this is happening either as I thought the RouteConfig file was purely to tell the application where to inialise.
Code below, some points to make:
This is what the URL looks like when I am about to submit the application = https://localhost:44313/Service/AddApplication?Course=Level1&DriverId=1&UserId=2
RoutesConfig is sending to "GetUser", "User", 1 at application start
The viewbags are working as I can see that it picks up the correct UserId at the very end of the adding process.
Controller Action to Add Application;
[HttpPost]
public ActionResult AddNewApplication(ApplicationAdd applicationAdd, string UserId, int DriverId)
{
try
{
// TODO: Add insert logic here
applicationService.AddApplication(applicationAdd, UserId, DriverId);
return RedirectToAction("GetUser", "User", new { UserId = ViewBag.UserId });
}
catch
{
return View();
}
}
GetUser action in User Controller:
public ActionResult GetUser(string id)
{
return View(userService.GetUser(id));
}
GetUser action in userService:
public User GetUser(string id)
{
using (var context = new MyContext())
{
return userDAO.GetUser(id, context);
}
}
GetUser in userDAO:
public User GetUser(string id, MyContext context)
{
context.Users.Include(g => g.Applications).ToList();
return context.Users.Find(id);
}
RouteConfig file path:
defaults: new { controller = "User", action = "GetUser", id = 1 }
Controller Action that is giving the view to display the list of applications for a user:
public ActionResult GetApplications(string id)
{
User user = userService.GetUser(id);
IList<Application> applications = user.Applications.ToList();
return View(applications);
}
Try using this
RedirectToAction("GetUser", "User", new { id = ViewBag.UserId });
the parameter name UserId needs to be the same as the one in the funcation id.
In our developing e-commerce solution we are using AspNet Identity 2.2.1 and it is required that any guest (anonymous) users should complete checkout without prior registration to the website. In order to fullfill this requirement have written an ActionFilter named UserMigrationAttribute which obtains SessionTrackId (string GUID) from cookie -which we set from a HttpModule for every request if SessionTrackId is not found along with request cookies- and creates and actual IdentityUser in database with the username something like SessionTrackId#mydomain.com.
We have decorated our BaseController class with this UserMigration attribute in order to utilize its functions throughout the site.
Everything up to this point works as expected with single downside issue, which is when the page is being loaded for the first time for any user, if we try to make an Jquery Ajax Call to a Method which have [ValidateAntiForgeryToken] attribute, the call fails with the 'The provided anti-forgery token was meant for a different claims-based user than the current user.' error, even though we are sending __RequestVerificationToken parameter with every ajax call.
But if user opens another page by clicking link and/or reloads/refreshes current page, all the subsequent ajax calls complete successfully.
In our understanding UserMigrationAttribute creates user on OnActionExecuting method, but after we signIn user in the process #Html.AntiForgeryToken() is not being updated with the right values.
You may find the UserMigrationAttribute code below;
[AttributeUsage(AttributeTargets.Class)]
public class UserMigrationAttribute : ActionFilterAttribute
{
public ApplicationSignInManager SignInManager(ActionExecutingContext filterContext)
{
return filterContext.HttpContext.GetOwinContext().Get<ApplicationSignInManager>();
}
public UserManager UserManager(ActionExecutingContext filterContext)
{
return filterContext.HttpContext.GetOwinContext().GetUserManager<UserManager>();
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
CreateMigrateCurrentUser(filterContext);
base.OnActionExecuting(filterContext);
}
private static readonly object LockThis = new object();
private void CreateMigrateCurrentUser(ActionExecutingContext filterContext)
{
lock (LockThis)
{
var signInManager = SignInManager(filterContext);
var userManager = UserManager(filterContext);
var sessionTrackId = GetSessionTrackId(filterContext);
if (!filterContext.HttpContext.Request.IsAuthenticated)
{
if (!string.IsNullOrEmpty(sessionTrackId))
{
var username = string.Format("{0}#mydomain.com", sessionTrackId);
var user = userManager.FindByName(username);
if (user == null)
{
user = new User() {UserName = username, Email = username};
var result = userManager.Create(user);
userManager.AddToRole(user.Id, StringResources.AnonymousVisitorsGroup);
}
signInManager.SignIn(user, true, true);
}
}
else
{
if (!string.IsNullOrEmpty(sessionTrackId))
{
var username = string.Format("{0}#mydomain.com", sessionTrackId);
var user = userManager.FindByName(username);
if (user != null)
{
if (!HttpContext.Current.User.IsInRole(StringResources.AnonymousVisitorsGroup))
{
var targetUserId = HttpContext.Current.User.Identity.GetUserId<int>();
var service = new Service();
service.Users.MigrateUser(user.Id, targetUserId);
}
}
}
}
}
}
private string GetSessionTrackId(ActionExecutingContext filterContext)
{
var retVal = string.Empty;
if (filterContext.HttpContext.Request.Cookies["stid"] != null)
{
retVal = filterContext.HttpContext.Request.Cookies["stid"].Value;
}
return retVal;
}
}
Any help or suggestions are highly appreciated.
Thank you,
This is happening because the anti-forgery token is set in a cookie, which will not be updated until the next request. If you're manually signing a user in, you should also issue a redirect (even if to the same page they were already headed to), simply to ensure that the cookie data is correct. This normally happens naturally, as the sign in form will redirect to the URL that needed authorization after the user is signed in, thus negating the problem. Since you're not redirecting currently, the data is out of sync.
However, I have to say that this seems like a very poor solution to this particular use case. Creating some sort of temporary-type user and signing that user in to handle guest checkout creates an unnecessary glut of useless data in your database, at best, and leads to bugs and other issues like this one you're experiencing, at worst.
I also run an ecommerce site, and the way we handled guest checkout is incredibly simplistic. The checkout data is just stored in the session (email, shipping/billing address, etc.). We build a view model to handle the actual checkout where the data necessary for submitting the sale comes either from the user object, if they're logged in, or these session variables, if they aren't. If the user is neither logged in, nor has the requisite session variables set, then they are redirected to the onboarding form where billing/shipping, etc. is collected.
For other aspects like maintaining an anonymous cart, we use a permanent cookie with the cart identifier. If the user ends up creating an account, we associate the anonymous cart with their user, and then remove the cookie. This ensures that their cart survives past the session timeout and things like closing the browser, even if they're anonymous.
In other words, in all these things, no user object is actually needed. If it's there (user is logged in), great, we'll use it. Otherwise, we collect and persist the requisite information for checkout via other means.
I'm building a web app that is essentially a store, but I want to put in an easy way for the admin of the site to add new products. However I want to restrict this part of the site so only the admin can access it. I have no use for other users at this moment.
How do I make it so that anybody with the admin username and password can access these pages and it will persist to know that they are logged in? I already have a system in place that accepts a user input and then continues to the admin pages if it's correct. But the problem is if someone decides to just go directly to the pages like Admin/AddProduct. I'd need my app to know that they're not allowed to access the AddProduct page yet and redirect them back to the login.
Here's how you go about it Joey
You could do this easily by creating a CreateRoles method in your startup class. This helps check if the roles are created, and creates the roles if they aren't; on application startup. Like so.
private async Task CreateRoles(IServiceProvider serviceProvider)
{
//initializing custom roles
var RoleManager = serviceProvider.GetRequiredService<RoleManager<IdentityRole>>();
var UserManager = serviceProvider.GetRequiredService<UserManager<ApplicationUser>>();
string[] roleNames = { "Admin", "Store-Manager", "Member" };
IdentityResult roleResult;
foreach (var roleName in roleNames)
{
var roleExist = await RoleManager.RoleExistsAsync(roleName);
// ensure that the role does not exist
if (!roleExist)
{
//create the roles and seed them to the database:
roleResult = await RoleManager.CreateAsync(new IdentityRole(roleName));
}
}
// find the user with the admin email
var _user = await UserManager.FindByEmailAsync("admin#email.com");
// check if the user exists
if(_user == null)
{
//Here you could create the super admin who will maintain the web app
var poweruser = new ApplicationUser
{
UserName = "Admin",
Email = "admin#email.com",
};
string adminPassword = "p#$$w0rd";
var createPowerUser = await UserManager.CreateAsync(poweruser, adminPassword);
if (createPowerUser.Succeeded)
{
//here we tie the new user to the role
await UserManager.AddToRoleAsync(poweruser, "Admin");
}
}
}
and then you could call the await CreateRoles(serviceProvider); method from the Configure method in the Startup class.
ensure you have IServiceProvider as a parameter in the Configure class.
Question 2: "How do I make it so that anybody with the admin username and password can access these pages "
You can do this easily, like so.
[Authorize(Roles="Admin")]
public class ManageController : Controller
{
//....
Return View();
}
You can also use role-based authorization in the action method like so. Assign multiple roles, if you will
[Authorize(Roles="Admin")]
public IActionResult Index()
{
/*
.....
*/
}
While this works fine, for a much better practice, you might want to read about using policy based role checks. You can find it on the ASP.NET core documentation here, or this article I wrote about it here
Once you add ASP.NET Identity to your project you can implement Role based Authorization in your application. Basically it allows you to setup [Authorize(Roles = "Administrator")] attribute for contollers which shall be available for admin users only.
I have 5 roles of users.They are Admin,Distributor,Micro-distributor,Dealer and User.Admin has the privilege of accessing all pages of other user and all CRUD operations on it.All these users have different fields from others.If dealer register his details then the values stored into a register table in SQL server database.this is same for all roles.basic details of all users columns are same.but other details like bank details and shop details are extra columns of distributors and dealers.So you can store the registration details to one column or different columns.but user can login to their account based on their roles,that is if a dealer tries to login,then server must check such a dealer exist in the database.If yes then he redirect to his profile page.I need the complete model view and controller source code for this problem in mvc4 or mvc3.you canuse the sql server database for this action...
I use the following code snippet for login action
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Login(UserLogon u)
{
if (ModelState.IsValid)
{
using (TranzEntities2 dc = new TranzEntities2())
{
var v = dc.tbl_User.Where(a => a.user_name.Equals(u.user_name) && a.password.Equals(u.password)).FirstOrDefault();
if (v != null)
{
Session["LogedUserID"] = v.user_id.ToString();
Session["LogedUserFullname"] = v.first_name.ToString();
return RedirectToAction("Home");
}
else
{
ModelState.AddModelError("Error", "Login failed, Try again");
}
}
}
return View(u);
}
But it is for only one table.I need to check the user login based on their roles.Suppose if someone try to login then it automatically check the user belongs to which table.if he belongs to a dealer table then dealer page will redirect after login success.