I am using ASP.NET MVC 5. I am creating a registration page to register an "expert", which I want to be a separate role from a user. I see that in the pre-generated AspNetRoles table there is an ID, and a Name column. Every time I try and research this I get something that shows how to create a page for an admin on how to literally create roles. I just want to get that role in my database, and then be able to assign it to a user when they are created using the experts registration page. I don't want a page that can make roles, I want to be able to do this directly in visual studio.
Thanks.
Try this.
private ApplicationUserManager _userManager;
public ApplicationUserManager UserManager
{
get
{
return _userManager ??
HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
}
private set
{
_userManager = value;
}
}
Register User like this.
var user = new ApplicationUser {
UserName = "John Doe",
Email = "john.doe#foo.com"
};
// params: username and password
var result = await UserManager.CreateAsync(user, "name_birthday_cheeky");
if (result.Succeeded)
{
UserManager.AddToRole(user.Id, "expert");
//code omitted for brevity
}
Related
I have an application which requires role authorization using custom database. The database is set up with a tblUsers table that has a reference to a tblRoles table. The users are also already assigned to their roles.
I also want to use the [Authorize(Role = "RoleName")] attribute on each action to check if an authenticated user is assigned to "RoleName" in the database. I'm having a lot of trouble figuring out where I need to make a modification to the [Authorize] attribute so it behaves that way. I just want to see if a username has a role, I won't have a page to manage roles in the database.
I have tried implementing custom storage providers for ASP.NET Core Identity, but it's starting to look like this is not what I need because I'm not gonna be managing roles within the application, and I can't tell how it affects the behavior of [Authorize] attribute.
Also, it's likely that I have a false assumption in my understanding on how the [Authorize] attribute even works. If you notice it, I would appreciate if you could point it out.
I had a similar problem when my client asked for granular permissions for each role. I couldn't find a way to modify the Authorize attribute but was able to implement the solution with a custom attribute. But it depends on one thing i.e can you get the userId of the calling user? I used cookie authentication so I just include the userId in my claims when someone logs in so when a request comes I can always get it from there. I think the built-in Session logic in asp.net might get the job done too, I can't say for sure though. Anyways the logic for custom authorization goes like this:
Load users and roles from database to cache on startup. If you haven't set up a cache in your program (and don't want to) you can simply make your own for this purpose by making a UserRoleCache class with 2 static lists in it. Also there are several ways of loading data from db on startup but I found it easy to do that directly in Program.cs as you'll see below.
Define your custom attribute to check if the calling user has the required role by iterating over lists in cache and return 403 if not.
Modify your Program class like:
public class Program
{
public static async Task Main(string[] args)
{
IWebHost webHost = CreateWebHostBuilder(args).Build();
using (var scope = webHost.Services.CreateScope())
{
//Get the DbContext instance. Replace MyDbContext with the
//actual name of the context in your program
var context = scope.ServiceProvider.GetRequiredService<MyDbContext>();
List<User> users = await context.User.ToListAsync();
List<Role> roles = await context.Role.ToListAsync();
//You may make getters and setters, this is just to give you an idea
UserRoleCache.users = users;
UserRoleCache.roles = roles;
}
webHost.Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>();
}
Then comes the logic for checking if user has a role. Notice I've used an array of roles because sometimes you'll want to allow access to multiple roles.
public class RoleRequirementFilter : IAuthorizationFilter
{
private readonly string[] _roles;
public PermissionRequirementFilter(string[] roles)
{
_roles = roles;
}
public void OnAuthorization(AuthorizationFilterContext context)
{
bool hasRole = false;
//Assuming there's a way you can get the userId
var userId = GetUserId();
User user = UserRoleCache.users.FirstOrDefault(x => x.Id == userId);
//Where roleType is the name of the role like Admin, Manager etc
List<Role> roles = UserRoleCache.roles.FindAll(x => _roles.Contains(x.RoleType))
foreach(var role in roles)
{
if(user.RoleId == role.Id)
{
hasRole = true;
break;
}
}
if (!hasRole)
context.Result = new StatusCodeResult(403);
}
}
Finally make the Role attribute
public class RoleAttribute : TypeFilterAttribute
{
public RoleAttribute(params string[] roles) : base(typeof(RoleRequirementFilter))
{
Arguments = new object[] { roles };
}
}
Now you can use the Role attribute in your controllers:
public class SampleController : ControllerBase
{
[HttpGet]
[Role("Admin", "Manager")]
public async Task<ActionResult> Get()
{
}
[HttpPost]
[Role("Admin")]
public async Task<ActionResult> Post()
{
}
}
Based on this article and the source code in github associated with this tutorial I am trying to implement a mvc application where users have individual resources.
I have the authorize attribute on my controller and if I am not logged in I will be redirected to the login page. I can see my user name on the top of the page so I assume things are fine. But then I try a create action on another controller and finds that currentUser is null.
This seem to happen in a random way which makes it very frustrating. But lately only failing.
Could it be something with creation of the database? I'm using Code First.
[Authorize]
public class ShopsController : Controller
{
private ApplicationDbContext db;
private UserManager<ApplicationUser> manager;
public ShopsController()
{
db = new ApplicationDbContext();
manager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(db));
}
// GET: Shops
public ActionResult Index()
{
var currentUser = manager.FindById(User.Identity.GetUserId());
var shops = db.Shops.ToList().Where(shop => shop.Owner.Id == currentUser.Id);
return View(shops);
}
try this code (Note: the cast to string):
User.Identity.GetUserId<string>()
since my ID column in database was Id nvarchar(128),not null without cast i was receiving null but after cast it was giving me the expected GUID
In my project I am trying to retrieve all the users and their roles in MVC 5 using Entity Framework.
The DBContext is set up using Database first. But it is wearied that the AspNetUserRoles Table is not populated automatically and the relationship between AspNetUser and AspNetRole is many-to-many.
Below is the link to the screenshot.
Can anyone give me some hints on this? Many thanks.
If you want to manage the AspNetUsersRoles, you must make the following modification.
Remove the primary key, actually is conformed by UserId and RoleId
Add a new Id field in the table and check like primary key.
Update your model.
Now you can scaffolding this entity and create the controller and the view for manage this.
Note: Remember that by changing the primary key of this table on the DB side means you have to control how AspNetUserRoles records are created on the Application Side, considering you now could have record redundancy on the table, for instance:
MyRoles=1 (PK), UserID=1, RoleID=1, Comment= User1 is Admin
MyRoles=2 (PK), UserID=1, RoleID=2, Comment= User1 is Admin again
Which means the same, so manage this logic upon AspNetUserRoles creation!
I assume that there is no problem that you cannot see AspNetUserRoles table under EDMX at all.
You have access to this table via code and in most cases is enough.
Normally under ASP.NET MVC 5 you have something like
public class AccountController : Controller
{
private ApplicationUserManager _userManager;
...
public AccountController(ApplicationUserManager userManager, ApplicationSignInManager signInManager)
{
UserManager = userManager;
...
public ApplicationUserManager UserManager
{
get
{
return _userManager ?? HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
}
private set
{
_userManager = value;
}
}
So under Login method you can get user roles like this
[System.Web.Mvc.HttpPost]
[System.Web.Mvc.AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
...
var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, false, shouldLockout: false);
switch (result)
{
case SignInStatus.Success:
{
ApplicationUser user = UserManager.FindByName(model.Email);
var roles = (AppUserRoles[])Enum.GetValues(typeof(AppUserRoles));
foreach (var role in roles)
{
if (UserManager.IsInRole(user.Id, role.ToString()) && role == AppUserRoles.Administrators)
{
// Do what you need here
// logger.Info("Login attempt is success.");
return RedirectToAction("Index", "Admin");
}
You need also to have this enum in your code
public enum AppUserRoles
{
Administrators = 1,
Managers = 2,
Users = 3,
Others = 4
}
Another approach is to use STORED PROCEDURE that you can use in EDMX.
CREATE PROCEDURE GetUserRoleByUserId
#UserId nvarchar(128)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
SELECT [UserId],[RoleId] FROM [AspNetUserRoles] WHERE [UserId] LIKE #UserId
END
GO
Hope this will help you.
Because the roles are not seeded by default until you explicitly add them in your seed method
Read about Asp.Net Identity modules
http://www.asp.net/identity
http://www.codeproject.com/Articles/762428/ASP-NET-MVC-and-Identity-Understanding-the-Basics
I am trying to find the best way to structure my security roles in ASP.NET MVC.
Basically the Roles are static (Administrator, Client, Technician) but what they can do in each section is configurable, Add/Edit/Delete/View.
For example you are able to configure a Client's security to specific areas like User Accounts.
A user can be a combination of any roles, so it is possible to be a Client and a Technician and have the combined privlages of both users.
What would be a suitable way to go about doing this in ASP.NET MVC?
This is how we did it
public enum YourUserRoles
{
None = 0,
Admin = 1,
Consumer = 2
}
public class YourAuthorizeAttribute : FilterAttribute, IAuthorizationFilter
{
private readonly YourUserRoles[] _acceptedRoles;
public YourAuthorizeAttribute(params VoicelrUserRoles[] acceptedroles)
{
_acceptedRoles = acceptedroles;
}
public YourAuthorizeAttribute(params bool[] allowAll)
{
if (allowAll[0])
_acceptedRoles = new[] { VoicelrUserRoles.Admin, VoicelrUserRoles.Consumer };
}
public void OnAuthorization(AuthorizationContext filterContext)
{
if (SessionHelper.UserInSession == null)//user not logged in
{
string retUrl = filterContext.HttpContext.Request.RawUrl;
FormsAuthentication.SignOut();
filterContext.Result =
new RedirectToRouteResult(new System.Web.Routing.RouteValueDictionary {{ "controller", "home" },
{ "action", "index" },
{ "returnUrl", retUrl } });//send the user to login page with return url
return;
}
if (!_acceptedRoles.Any(acceptedRole => SessionHelper.UserInSession.Roles.Any(currentRole => acceptedRole == currentRole)))
{
filterContext.Result = new ViewResult
{
ViewName = "~/Views/Shared/Error.cshtml"
};
}
}
}
[YourAuthorize(YourUserRoles.Client )]
public ActionResult Whatever()
{
....
}
I would provide you this resolution:
Data Base
Users ([PK]Id, Name, etc.)
Roles ([PK]Id, Name, Description, etc.)
UserRoles ([PK]UserId, [PK] RoleId)
Users table stores information about users, like their names, emails, etc. Roles stores information about rolesm like its name, description, etc. UserRoles is just look-up table which you can use to tie specific user to specific role.
Code
In order to let your code to work with these tables, you can add your custom role provider where you will have enough facility with 2 methods that will be: public override string[] GetRolesForUser(string username) and public override bool IsUserInRole(string username, string roleName).
Usage
When you'll complete, you simply can use Authorize attributes [Authorize(Roles = "Administrators")] to check if user has access to specific action or controller or you can use Razor verification in order to show/hide some html based on users role #User.IsInRole("Administrator")
Please check following links for more info
Custom Role Provider for MVC
Custom Membership and Role provider in ASP.NET MVC 4
Initially you can check the user exist in how many roles?
Create a view to show the Roles and write the message "please select a role to proceed "
After choose the user type proceed the user as the selection.
I have a project called Authorization with CodeFirstRoleProvider class that inherits from default RoleProvider
public class CodeFirstRoleProvider : RoleProvider
{
public override void CreateRole(string roleName)
{
if(string.IsNullOrEmpty(roleName)) return;
using(var context = new SISContext())
{
var role = context.Roles.SingleOrDefault(rl => rl.RoleName == roleName);//Roles table exists in database
if(role == null)
{
var newRole = new Role
{
RoleId = Guid.NewGuid(),
RoleName = roleName
};
context.Roles.Add(newRole);
context.SaveChanges();
}
}
}
}
In my other project WebPortal I want to use above method in let's say following way
var _role = new CodeFirstRoleProvider();
_role.CreateRole("Admin");
_role.CreateRole("NonAdmin");
now where do I need to place this code in my webportal? so that these roles gets added to database for the first time when the application runs.
Suppose this program runs for first time and someone clicks the register button I want to have a dropdownlist with above roles mentioned. So, these roles need to be in database before register is clicked.
Once the roles are in database I don't need to worry for the accessing these values in future.
One way would be manually writing the value in database but I don't want to do that, since I have this function I can use.
What If I do something like this?
[AllowAnonymous]
public ActionResult Login(string returnUrl)
{
var _role = new CodeFirstRoleProvider();//remove after role is added to database
_role.CreateRole("Admiin");//remove after role is added to database
_role.CreateRole("NonAdmin");//remove after role is added to database
ViewBag.ReturnUrl = returnUrl;
return View();
}
and once the roles are added to database i remove those code that does role adding.
Take a look at this article on seeding the SimpleMembership database. Even if you are not using the SimpleRoleProvider the same principals should apply since you are using code-first.