I have a class called User and it has a property of List <Role>.
Using dependency injection how do I populate the Roles given that I need to know the user first? I.e. the roles are dependent on the user so I can't inject them on instantiation as I do not know the user at this point as I need to first call a method like GetUser (username); which returns a user object.
Update
This is the class structure I have
public partial class User:IUser
{
private List<IUserRole> _userRoles = new List<IUserRole>();
public User()
{
}
public User GetUserByID(int id, dbEntities context)
{
User user = new User();
using(context)
{
user = (from u in context.Users where u.ID == id select u).FirstOrDefault();
}
return user;
}
public User GetUser(string username, string password, dbEntities context)
{
User user = new User();
using (context)
{
user = (from u in context.Users where u.Username==username && u.Password==password select u).FirstOrDefault();
}
return user;
}
List<IUserRole> UserRoles
{
get
{
return _userRoles;
}
set
{
_userRoles = value;
}
}
}
As you can see, a populated user object is retrieved via various methods. However I really want the UserRoles to be returned with the object too but injecting the roles would not work as they can not be retrieved until the user is populated.
Having directly accessible List<Roles> forces you populate the list at the moment User is created. It means your "factory" for the User object need to also call "role provider" to obtain list of roles for the user.
Assuming you are using some DI container like Unity code would look similar to:
_container.RegisterFactory(container =>
{
var user = new User();
user.Roles = container.Resolve<IRolesProvider>()
.GetRolesForUser(user);
return user;
});
Alternatively you can add dependency to "roles provider" to User and compute (possibly with caching) on demand:
class User
{
IRolesProvider roles;
public User(IRolesProvider roles,....)
{
this.roles = roles;
...
}
public List<Roles> { get { return roles.GetRolesForUser(this);}}
...
}
Related
Using this answer, I implemented below code to get list of ApplicationUsers in a specific role.
I need to mention that ApplicationUser is an extention of IdentityUser. I want to know are there any better methods for this?
ApplicationDbContext context = new ApplicationDbContext();
var store = new Microsoft.AspNet.Identity.EntityFramework.UserStore<ApplicationUser>(dbContext);
var manager = new Microsoft.AspNet.Identity.UserManager<ApplicationUser>(store);
List<ApplicationUser> users = new List<ApplicationUser>();
foreach (ApplicationUser user in manager.Users.ToList())
{
if (manager.IsInRole(user.Id,"Admin")){
users.Add(user);
}
}
You can query like this
ApplicationDbContext context = new ApplicationDbContext();
var role = context.Roles.SingleOrDefault(m => m.Name == "Admin");
var usersInRole = context.Users.Where(m => m.Roles.Any(r => r.RoleId != role.Id));
I am not sure if this is the optimal way, but does less queries to database than your code.
No, there isn't better way.
But assuming you are using that in your controller you could create a BaseController where every other controller is derived from.
Inside that BaseController you can instantiate the ApplicationManager and create a method that optionally receives an ID (UserId) and returns a bool.
Which you could call in your controller like this:
if(HasRole("Owner")) {} // CurrentUser
if(HasRole(Id, "Owner")) {} // Specific User
There are other ways, but that's a developer choise.
Note
Keep in mind that if you choose to statically instantiate the ApplicationManager, it will run only once which may do things that you don't want, like adding a user to a specific role and that ApplicationManager not showing the new role unless it is created again.
I suggest below method:
public static bool isInRole(IPrincipal User, string roleName, ApplicationDbContext dbContext)
{
try
{
var store = new Microsoft.AspNet.Identity.EntityFramework.UserStore<ApplicationUser>(dbContext);
var manager = new Microsoft.AspNet.Identity.UserManager<ApplicationUser>(store);
return manager.IsInRole(User.Identity.GetUserId(), roleName);
}
catch (Exception ex)
{
return false;
}
return false;
}
I am trying to populate a view model with User data that includes a list of the user's associated roles. Currently, my method is as follows:
[EnableQuery]
[AcceptVerbs("GET")]
public IEnumerable<UserViewModel> Get()
{
var clientId = this.GetClientId();
var users = this.UserManager.Users.Where(x => x.ClientId == clientId).ProjectTo<UserViewModel>().ToList();
foreach (UserViewModel user in users)
{
user.UserRoles = this.UserManager.GetRoles(user.Id);
}
return users;
}
Is there a better way to perform this operation? I cannot create a Linq query because EF will not allow me to create a class for the AspNetUserRoles table, and it will not allow me to edit the AspNetUsers table directly - so I am using the UserManager to get the results instead.
I have a database table where all the company employees are listed. They have roles (a, b, c) defined to each employee. for e.g. employee 1 has role a, employe 2 has role b and so on.
Now, i want to check if employe has either of the 3 roles. if yes, provide that user access to website. if no roles mentioned to that user, deny access. The c# code should be able to take the windows login information and then query the database.
can anyone please let me know how to use C# code and start off with things
A Filter Attribute that extends AuthorizeAttribute. It gets the roles for the user in the database and compares with the roles assigned to each controller or method.
public class UserRoleAuthorize : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
//Data Repository. Getting data from database
var repository = new LoginRoleRepository();
//GetCharacterSeparator is an Extension method of String class
//It seperates the comma separated roles.
//The data comes from the controller
var roles = Roles.GetCharacterSeparator(',', true);
if (httpContext.User.Identity.IsAuthenticated)
{
//Here I check if the user is in the role, you can have your own logic. The data is gotten from DB.
var userRoles =
repository.All().Where(obj => obj.Login.Username == httpContext.User.Identity.Name).Single().Roles;
foreach (var role in roles)
if (userRoles.Any(obj => obj.Name == role))
return true;
}
return false;
}
}
Then you just define the attribute for each method or controller as bellow.
//Both Doctors and Receptionist have access to Patient controller.
[UserRoleAuthorize(Roles="Doctors, Receptionist")]
public class PatientController : Controller
{
//Both Doctors and Receptionist have access to Schedule an appointment for patients.
public ActionResult Schedule()
{
return View();
}
//Only Doctors have access to Treat patients.
[UserRoleAuthorize(Roles="Doctors")]
public ActionResult TreatPatient()
{
return View();
}
}
You need to add extra information as:
//Here seperate the roles as Doctor:ReadWrite, Receptionist:Read
//If you see Doctor:ReadWrite means the doctor has Read and Write and so on.
//This code is in AuthorizeCore
var roles = Roles.GetCharacterSeparator(',', true);
//And Add the bellow to the controllers and methods.
[UserRoleAuthorize(Roles="Doctors:Write, Employees:Read")]
I had a problem when using identity user. After call the Update(user), the record in database has been changed. The problem occur when I call Method(string userId) again, contain FindById(userId). The FindById(userId) returns a user with all record still remain as the first although I has updated it before.
I implement user table:
public class ApplicationUser : IdentityUser
{
public int MyProperty { set; get; }
}
The user manager class:
public class ApplicationUserManager : UserManager<ApplicationUser>, IApplicationUserManager
{
public Task MethodAsync(string userId)
{
// Find user
// return object before change (MyProperty not equal 1)
ApplicationUser user = await base.FindByIdAsync(userId);
user.MyProperty = 1;
await base.UpdateAsync()
}
}
Does it happen only when you are updating the current logged-in user's properties? If so, try to re-sign in again:
SignInManager.SignIn(user, false, false)
The user object can be gotten from the UserManager.FindById method.
I'm using asp.net MVC5 and asp.net Identity v2 (from the nightly releases) but I think this question still applies to Identity V1.
I have a membership system and i am linking a AspNetUser entity to my membershipuser entity via a field AspUserId in the membershipuser table.
public partial class membershipuser
{
public int id { get; set; }
public string full_name { get; set; }
public string address { get; set; }
public string AspNetUserId { get; set; }
.....
}
I was wondering what is the best method of caching your membershipuser record for the life of the request. This way:
public static class extensions
{
public static membershipuser GetMember(this System.Security.Principal.IPrincipal User)
{
string currentUserId = User.Identity.GetUserId();
return new MemberEntities().membershipusers.FirstOrDefault(m => m.AspNetUserId == currentUserId );
}
}
Or this way:
public abstract partial class BaseController : Controller
{
private membershipuser _Member;
public membershipuser Member
{
get {
if(_BASRaTMember == null)
{
string currentUserId = User.Identity.GetUserId();
BASRaTMember = new BasratEntities().tbl_basrat_members.FirstOrDefault(m => m.AspNetUserId == currentUserId );
}
return _BASRaTMember;
}
private set { _BASRaTMember = value; }
}
}
I'm thinking the Basecontroller method is best as I'm guessing if I called the extension method 5 times to check member properties it would query the database for the user 5 times. Or would it be better to somehow store it against the request? My sole intention is to reduce the database lookups for the requests after the user has been authenticated.
So this is less of an issue in 2.0 if you follow the samples pattern of using a single DbContext per request(OwinContext) as the DbContext does this kind of caching itself. But you could explicitly cache users by their UserId as well if you wanted to guarantee this caching irrespective of the specific store caching behavior, you would need to go through some kind of helper method instead of directly using the user manager. The helper would take care of populating the cache, i.e. something like this
public async Task<TUser> GetUser(this IOwinContext context, TKey userId, UserManager<TUser, TKey> manager) {
var contextKey = "computeYourCacheKey"+userId;
var user = context.Get<TUser>(contextKey);
if (user == null) {
user = await manager.FindByIdAsync(userId);
context.Set<TUser>(userId, user);
}
return user;
}