Using asp.net mvc5, my user management systems seems to work. I can login with google or with name/password..
but now I am working on a user management interface in which I need to be able to delete existing users. And this is starting to expose to me just how confusing the user management system is. There's so many different ways to deal with users.. and some of them don't work.
Most everywhere I read, it is talking about using the Membership.DeleteUser().
But that isn't working...
The users were created with.
var user = new ApplicationUser()
{
UserName = model.UserName,
Email = model.Email,
ConfirmationToken = confirmationToken,
IsConfirmed = false
};
var result = await UserManager.CreateAsync(user, model.Password);
Now later on.. how do I delete such a user? (given its name or userid)
I have tried what comes up most on various searches.. comes up with Membership as the solution. But this surely isn't right for MVC5?
For example
var allusers = Membership.GetAllUsers(); // allusers is empty
bool success = Membership.DeleteUser(model.name); // <-- success = false
I can get all the users using this method..
ApplicationDbContext db = new ApplicationDbContext();
foreach (var user in db.Users) { ... }
And I can find an individual user with..
ApplicationDbContext db = new ApplicationDbContext();
var um = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(db));
ApplicationUser user = um.FindById(model.userId);
Now how do I delete one though? ....
Update
As of Microsoft.AspNet.Identity Version 2.0.0.0, you can now delete users with Identity using UserManager.Delete(user);.
For Posterity
You are referring to two different things, Identity and Membership. Newer versions of ASP.NET support Identity and Membership with Identity being the default, while older versions support only Membership (out of those two authentication systems).
When you create a user with UserManager.CreateAsync, you are doing so within the Microsoft.AspNet.Identity namespace. When you are attempting to delete a user with Membership.DeleteUser, you are doing so within the System.Web.Security namespace. They are living in two different worlds.
As another comment mentions, deleting users is not yet supported out of the box by Identity, but it is the first item on their roadmap for a Spring of 2014 release.
But why wait? Add another property to the ApplicationUser model like this:
public class ApplicationUser : IdentityUser
{
public string IsActive { get; set; }
}
Then, in your controller for deleting a user:
user.IsActive = false;
Do a check when the user logs in:
if (user.IsActive == false)
{
ModelState.AddModelError(String.Empty, "That user has been deleted.");
return View(model);
}
When an deleted user attempts to re-register, instead of UserManager.Create, use UserManager.Update with their new information on the registration page.
These steps will effectively delete the user. If you truly must clear their information from your database, you can use Entity Framework to do that more directly.
added to the previous response. If you have
public class ApplicationUser : IdentityUser
{
public string IsActive { get; set; }
}
Then, in your controller for deleting a user:
user.IsActive = false.ToString();
because your data type is a string and n ot a boolean
Related
since I am rather new to SignalR and couldn't really find anything online, I want to ask my questions here.
I use SignalR with C# and .Net-Framework and want to Implement a function in which i can login with Username and Password to the Host/Hubs with specific Roles, but I couldn't really find anything helpfull in this regard at the Microsoft Docs.
(https://learn.microsoft.com/en-us/aspnet/signalr/overview/security/hub-authorization)
So my Question is:
How can I implement Authentication on my SignalR-Host and is it possible to reject a connection if a the Username and Password which is send to the Host isn't correct?
Thanks for the Help
DerDane
I use an Attribute for that:
public class AuthorizeRolesAttribute : AuthorizeAttribute
{
public AuthorizeRolesAttribute(params string[] roles)
{
this.Roles = string.Join(",", roles);
}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (httpContext == null)
{
throw new ArgumentNullException(nameof(httpContext));
}
// Make sure the user is authenticated.
var roles = this.Roles.Split(new [] { ',' }, StringSplitOptions.RemoveEmptyEntries);
foreach (var role in roles)
{
if (httpContext.User.IsInRole(role))
{
return true;
}
}
return false;
}
}
Usage:
[AuthorizeRoles("Admin")]
public class ExampleHub...
UPDATE
Authentication is not a trivial topic. If you want to dive deeper into it, take a look at https://learn.microsoft.com/en-us/aspnet/core/security/authentication/?view=aspnetcore-6.0 to understand how to authenticate a user. Then, at https://learn.microsoft.com/en-us/aspnet/core/security/authorization/roles?view=aspnetcore-6.0 you can see how roles are associated with a previously authenticated identity.
Generally, you will never do this manually. You use existing frameworks, which are already proven.
In httpContext.User.Identity you have access to your identity, the logged in user.
I think it can be very interesting for you to understand the pipeline of ASP .NET. Search for "asp net pipeline diagram" and also check this
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/middleware/?view=aspnetcore-6.0 for more information about the middleware.
There is a lot going on behind the scenes. You can just use them but it's always interesting to know them to a greater or lesser extent.
You define the roles. If your application is to manage a restaurant, you can create roles such as "waiter", "cook"... while in an educational center they can be "teacher", "student", "director", etc.
You can get a list of roles like this:
var roleStore = new RoleStore<IdentityRole>(context);
var roleMngr = new RoleManager<IdentityRole>(roleStore);
var roles = roleMngr.Roles.ToList();
To add a role to user, you can use UserManager.AddToRole.
This is truly one of the strangest issues I've run into.
I have a Web API which uses EF. I have an audit table which takes an ApplicationUser. I create the new object, add it to the collection and then call SaveChangesAsync(). The weird part is, I get "User name MyUserName is already taken." error.
using (var context = new ApplicationDbContext())
{
var user = context.Users.Single<ApplicationUser>(x => x.UserName == model.UserName);
var sid = context.SessionIds.FirstOrDefault(x => x.Id == model.SessionId);
var audit = new Audit
{
Data = model.Data,
User = user,
IpAddress = Helper.GetClientIp(Request),
Session = sid != null ? sid : ItsMyChance.Entities.Entities.SessionId.Create(scoreModel.UserName, scoreModel.GameId)
};
context.Audits.Add(audit);
await context.SaveChangesAsync();
}
Update
This code has been working for years. The difference is I upgrade from .NET 4.5 to .NET 4.61
Update 2
I also tried the following but still receive the same error
[ForeignKey("User")]
public string UserId { get; set; }
public ApplicationUser User { get; set; }
Update 3
Trying to track this issue down I call
var entries = context.ChangeTracker.Entries();
It returns several entries, 1 for each object, including User. User shows Added and another as Unchanged. I can't figure out how this is happening.
In addition, I added the following before making any changes but there's no effect.
context.Configuration.AutoDetectChangesEnabled = false;
Since You are adding the complete user object in Audit , so SaveChangesAsync will save a new Entry for Audit and User also and since a user with same username already exists that's why you are getting this error. What you should do is just assign just the UserId (Whatever is referral key in Audit table for User) in Audit object
var audit = new Audit
{
Data = model.Data,
UserId = user.Id,
IpAddress = Helper.GetClientIp(Request),
Session = sid != null ? sid : ItsMyChance.Entities.Entities.SessionId.Create(scoreModel.UserName, scoreModel.GameId)
};
I am now learning ASP.NET MVC 5 and working on a little project to improve my knowledge.
Using Entity Framework, I didn't see until now a table for the Users although there is a login and register functionality.
I wonder for example: what shall I do when I want show the data related to a specific user? With a code like that:
public ActionResult MyAnnoncement()
{
if (!User.Identity.IsAuthenticated)
{
return View("~/Views/Account/Login.cshtml");
}
else
{
return View(db.Voitures.ToList());
}
}
You can use User.Identity.GetUserId() to get the ID of the user from the AspNetUsers table, then populate the User object like this:
ApplicationDbContext db = new ApplicationDbContext();
string uid = User.Identity.GetUserId();
ApplicationUser u = db.Users.Find(uid);
Please note you'll need to add "using Microsoft.AspNet.Identity;" at the top of your code to use User.Identity.GetUserId().
You need an instance of the UserManager "ApplicationUser can be different in your case can by some other object
Then you can do something like this
var user = UserManager.FindById(User.Identity.GetUserId());
the user object has your data
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.
in ASP MVC5 RC I didn't get the role system to work.
My database has all needs tables an role exist but proofing if user is in role always return false (no SQL exception or something)!?
Did I need to activate role system for IPrincipal somewhere?
Test code:
AccountController accCont = new AccountController();
// check role exist : result = true
var roleExist = await accCont.IdentityManager.Roles.RoleExistsAsync("61c84919-72e2-4114-9520-83a3e5f09de1");
// try find role by name : result = role object
var role = await accCont.IdentityManager.Roles.FindRoleByNameAsync("ProjectAdministrator");
// check with AccountController instance : result = true
var exist = await accCont.IdentityManager.Roles.IsUserInRoleAsync(User.Identity.GetUserId(), role.Id);
// check if current user is in role : result (both) = false????
var inRole = User.IsInRole(role.Id);
var inRole2 = User.IsInRole(role.Name);
I also try to build an custom extenuation like the IIdentity.GetUserId() extension method from Microsoft.AspNet.Identity.Owin Namespace.
namespace Microsoft.AspNet.Identity
{
public static class IdentityExtensions
{
public static string IsUserInRole(this IIdentity identity)
{
if (identity == null)
{
throw new ArgumentNullException("identity");
}
ClaimsIdentity identity2 = identity as ClaimsIdentity;
if (identity2 != null)
{
var result = identity2.FindFirstValue(IdentityConfig.Settings.GetAuthenticationOptions().RoleClaimType);
return null; // later result
}
return null;
}
}
}
But the result for claim Type RoleClaimType is always null :(
I'm really stuck with this.
Thank you for your help! Steffen
I'm trying to understand how to use roles in MVC 5 myself, which is what brought me here. I can't answer your question, but check out this link. The downloaded solution works right out of the box and I've already been able to cut-and-paste some of the code and get it working in my own app. Now I'm trying to fully understand what it's doing.
http://www.typecastexception.com/post/2013/11/11/Extending-Identity-Accounts-and-Implementing-Role-Based-Authentication-in-ASPNET-MVC-5.aspx
It may not answer your question but at least it's a fully working solution that actually does work as described without a lot of hassle, so it's a good starting point.
User.IsInRole is basically looking at the claims for the currently signed in user. What does your sign in logic look like? That is what is responsible for minting the cookie that turns into the User identity. That needs to have the Role claim set properly for the IsInRole method to work correctly.