Update User Entity Framework - entity-framework-4

I am writing an asp.net membership provider using Entity code first and I need some help understanding how to Update the MembershipUser object.
The UpdateUsert(MembershipUser user) override method needs to be implemented and consists of a MembershipUser parameter.
The following code does not work and I am not sure how to tie the MembershipDBContext with the supplied membership user so that the user is updated. Thanks for the help.
public override void UpdateUser(MembershipUser user)
{
MembershipDBModel userToUpdate = _getMembershipDBModelUser(user.UserName);
userToUpdate.IsLockedOut = user.IsLockedOut;
using (MembershipDBContext db = new MembershipDBContext())
{
db.SaveChanges();
}
}

Why not use the built in functionality for the MembershipProvider?
MembershipUser user = Membership.GetUser();
user.IsApproved = false;
Membership.UpdateUser(user);

Related

Permission Based Authorization with ASP.Net Identity 2

I'm working on a ASP.Net MVC 5 app and using ASP.Net identity 2, and need to authorize users based on roles and permissions. roles and permissions is not related to each other. for example, to access "action1" action method,( "admin" role ) or ( combination of "role1" and "permission1" ) must exist for him, but other users that is not in "admin" role or combination of ( "role1" and "permission1") is not true for theirs, don't allow to access that action method.
how i can do this scenario?
do claims based authorization useful in this manner?
or i must implement Permission entity and custom AuthorizeAttribute? if true how?
best regards
Check out the ResourceAuthorize attribute in the Thinktecture.IdentityModel.Owin.ResourceAuthorization.Mvc package.
This attribute authorizes a user based on an action (e.g. read) and a resource (e.g. contact details). You can then base whether or not they are allowed to perform that action on a resource based on a claim (e.g. their presence in a role).
See here for a good example.
Might not be exactly what you are looking for, but you can take inspiration and implement your own authorization attribute using similar logic.
This is custom made Authorize which checks permission from database.
For example you have 3 bools for permission Account,Clients,Configuration
and you want to restrict user based on them.
you can add even two permission on one action, for example you have a method which can be accessed by Account and Client permission than you can add following line
Modify this to use roles with permissions in this, this is the easiest and best way to handle it.
[PermissionBasedAuthorize("Client, Account")]
This method below is which check the bools from database.
public class PermissionBasedAuthorize : AuthorizeAttribute
{
private List<string> screen { get; set; }
public PermissionBasedAuthorize(string ScreenNames)
{
if (!string.IsNullOrEmpty(ScreenNames))
screen = ScreenNames.Split(',').ToList();
}
public override void OnAuthorization(HttpActionContext actionContext)
{
base.OnAuthorization(actionContext);
var UserId = HttpContext.Current.User.Identity.GetUserId();
ApplicationContext db = new ApplicationContext();
var Permissions = db.Permissions.Find(UserId);
if (screen == null || screen.Count() == 0)
{
actionContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized);
}
bool IsAllowed = false;
foreach (var item in screen)
foreach (var property in Permissions.GetType().GetProperties())
{
if (property.Name.ToLower().Equals(item.ToLower()))
{
bool Value = (bool)property.GetValue(Permissions, null);
if (Value)
{
IsAllowed = true;
}
break;
}
}
if (!IsAllowed)
{
actionContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized);
}
}
}
I implemented a Permission-based extension for Microsoft Identity 2 membership system. But in this extension, permissions and roles are related together. there is a many-to-many relation between them. Also you can have a complex authentication with combination of roles and permissions. I suppose it can help you to do permission based authentication.
You can do permission authentication in two ways:
First approach:
// GET: /Manage/Index
[AuthorizePermission(Name = "Show_Management", Description = "Show the Management Page.")]
public async Task<ActionResult> Index(ManageMessageId? message)
{
//...
}
Second approach:
// GET: /Manage/Users
public async Task<ActionResult> Users()
{
if (await HttpContext.AuthorizePermission(name: "AllUsers_Management", description: "Edit all of the users information."))
{
return View(db.GetAllUsers());
}
else if (await HttpContext.AuthorizePermission(name: "UnConfirmedUsers_Management", description: "Edit unconfirmed users information."))
{
return View(db.GetUnConfirmedUsers());
}
else
{
return View(new List<User>());
}
}
Also it's an open source and free extension and you can access to the repository here.

MVC 5 - retrieving the ApplicationUser object

I am developing a MVC 5 internet application and have a question in regards to having a custom object in the ApplicationUser object.
I have a public virtual Account account object in the ApplicationUser object that holds many maximum count variables for objects in my MVC 5 application. This is set for each user when a user registers an account.
Before I create a model object, I check to see if the user has not exceeded their maximum count for the model object. This is done in a service class for the object.
Here is an example of the code used for a file object:
var userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
ApplicationUser user = userManager.FindByNameAsync(userName).Result;
int maxFiles = user.account.maxFiles;
I am using many service classes for many objects with similar code to retrieve the ApplicationUser object.
My question is this: Rather than retrieving the ApplicationUser object each time, for each service class, is it possible to store this object when the user logs on, and then refer to this object before a model object is created? If so, where can I store this object for the above purpose?
Also, how much memory/bandwidth is used when retrieving the ApplicationUser object? Is there minimal memory/bandwidth used such that I do not need to worry about memory/bandwidth when retrieving the ApplicationUser object each time before I create a model object?
Thanks in advance.
That is a typical case for adding a claim with a value on logged-in identity.
When user logs in you add a claim with this value. Value of this claim is then persisted in the cookie. And is available every time user comes back and this is very fast look-up that is happening anyway for cookie authentication.
To add this claim to the identity, you need to override CreateIdentityAsync method on ApplicationUserManager:
public override async Task<ClaimsIdentity> CreateIdentityAsync(ApplicationUser user, string authenticationType)
{
var identity = await base.CreateIdentityAsync(user, authenticationType);
identity.AddClaim(new Claim("MyApplication:maxFiles", user.account.maxFiles));
return identity;
}
Then to access this you can create an extension method:
public static int GetMaxFiles(this IPrincipal principal)
{
if (principal == null)
{
throw new ArgumentNullException("principal");
}
var claimsPrincipal = principal as ClaimsPrincipal;
if (claimsPrincipal == null)
{
throw new DomainException("User is not authenticated or IPrincipal is not ClaimsPrincipal");
}
var claim = claimsPrincipal.Claims.FirstOrDefault(c => c.Type == "MyApplication:maxFiles");
int maxfiles = 0;
if(int.TryParse(claim.Value, out maxfiles))
{
return maxfiles;
}
throw new Exception("Claim value is not an integer")
}
And in your application you can use it as var maxFiles = HttpContext.Current.User.GetMaxFiles(). Or if it is a Controller or a View, then you can do var maxFiles = User.GetMaxFiles().
This is very fast lookup and does not reach into your database.

Updating user data - ASP.NET Identity

I've added custom fields to the ApplicationUser class
I've also created a form through which the user can enter/edit the fields.
However for some reason I'm not able to update the fields in the database.
[HttpPost]
[ActionName("Edit")]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Manage(EditProfileViewModel model)
{
if (ModelState.IsValid)
{
// Get the current application user
var user = User.Identity.GetApplicationUser();
// Update the details
user.Name = new Name { First = model.FirstName, Last = model.LastName, Nickname = model.NickName };
user.Birthday = model.Birthdate;
// This is the part that doesn't work
var result = await UserManager.UpdateAsync(user);
// However, it always succeeds inspite of not updating the database
if (!result.Succeeded)
{
AddErrors(result);
}
}
return RedirectToAction("Manage");
}
My problem is similar to MVC5 ApplicationUser custom properties, but that seems to use an older version of Identity because the IdentityManager class doesn't seem to exist.
Can someone guide me on how to update User info in the database?
UPDATE:
If I include all the fields in the register form, all the values are stored in the appropriate field in a new record of the Users table from the database.
I don't know to make changes to the fields of an existing user (row in the users table). UserManager.UpdateAsync(user) doesn't work.
Also note my issue is more Identity oriented than EntityFramework
OK... I spent hours trying to figure why userManager.updateAsync would not persist the user data that we edit ... until I reached the following conclusion:
The confusion arises from the fact that we create the UserManager in one line like this:
var manager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new MyDbContext()));
...then we use manager.UpdateAsync( user ); but that will update the user in the context, and then we will need to save changes to the dbcontext of the Identity. So, the question is how to get the Identity DBcontext in the easiest way.
To solve this, we should not create the UserManager in one line ... and here is how I do it:
var store = new UserStore<ApplicationUser>(new MyDbContext());
var manager = new UserManager(store);
then after updating the user by calling
manager.UpdateAsync(user);
then you go to the context
var ctx = store.context;
then
ctx.saveChanges();
wahooooooo...persisted :)
Hope this will help someone who pulled their hair for a few hours :P
If you leave any of the fields for ApplicationUser OR IdentityUser null the update will come back as successful but wont save the data in the database.
Example solution:
ApplicationUser model = UserManager.FindById(User.Identity.GetUserId())
Add the newly updated fields:
model.Email = AppUserViewModel.Email;
model.FName = AppUserViewModel.FName;
model.LName = AppUserViewModel.LName;
model.DOB = AppUserViewModel.DOB;
model.Gender = AppUserViewModel.Gender;
Call UpdateAsync
IdentityResult result = await UserManager.UpdateAsync(model);
I have tested this and it works.
The OWIN context allows you to get the db context. Seems to be working fine so far me, and after all, I got the idea from the ApplciationUserManager class which does the same thing.
internal void UpdateEmail(HttpContext context, string userName, string email)
{
var manager = context.GetOwinContext().GetUserManager<ApplicationUserManager>();
var user = manager.FindByName(userName);
user.Email = email;
user.EmailConfirmed = false;
manager.Update(user);
context.GetOwinContext().Get<ApplicationDbContext>().SaveChanges();
}
The UserManager did not work, and As #Kevin Junghans wrote,
UpdateAsync just commits the update to the context, you still need to save the context for it to commit to the database
Here is quick solution (prior to new features in ASP.net identity v2) I used in a web forms projetc. The
class AspNetUser :IdentityUser
Was migrated from SqlServerMembership aspnet_Users. And the context is defined:
public partial class MyContext : IdentityDbContext<AspNetUser>
I apologize for the reflection and synchronous code--if you put this in an async method, use await for the async calls and remove the Tasks and Wait()s. The arg, props, contains the names of properties to update.
public static void UpdateAspNetUser(AspNetUser user, string[] props)
{
MyContext context = new MyContext();
UserStore<AspNetUser> store = new UserStore<AspNetUser>(context);
Task<AspNetUser> cUser = store.FindByIdAsync(user.Id);
cUser.Wait();
AspNetUser oldUser = cUser.Result;
foreach (var prop in props)
{
PropertyInfo pi = typeof(AspNetUser).GetProperty(prop);
var val = pi.GetValue(user);
pi.SetValue(oldUser, val);
}
Task task = store.UpdateAsync(oldUser);
task.Wait();
context.SaveChanges();
}
I also had problems using UpdateAsync when developing a version of SimpleSecurity that uses ASP.NET Identity. For example, I added a feature to do a password reset that needed to add a password reset token to the user information. At first I tried using UpdateAsync and it got the same results as you did. I ended up wrapping the user entity in a repository pattern and got it to work. You can look at the SimpleSecurity project for an example. After working with ASP.NET Identity more (documentation is still non-existent) I think that UpdateAsync just commits the update to the context, you still need to save the context for it to commit to the database.
I have tried the functionality in the same way and when i call UserManager.Updateasync method it succeeds but there is no update in the database. After spending some time i found another solution to update the data in aspnetusers table which is following:
1) you need to create UserDbContext class inheriting from IdentityDbContext class like this:
public class UserDbContext:IdentityDbContext<UserInfo>
{
public UserDbContext():
base("DefaultConnection")
{
this.Configuration.ProxyCreationEnabled = false;
}
}
2) then in Account controller update user information like this:
UserDbContext userDbContext = new UserDbContext();
userDbContext.Entry(user).State = System.Data.Entity.EntityState.Modified;
await userDbContext.SaveChangesAsync();
where user is your updated entity.
hope this will help you.
Excellent!!!
IdentityResult result = await UserManager.UpdateAsync(user);
Based on your question and also noted in comment.
Can someone guide me on how to update User info in the database?
Yes, the code is correct for updating any ApplicationUser to the database.
IdentityResult result = await UserManager.UpdateAsync(user);
Check for constrains of all field's required values
Check for UserManager is created using ApplicationUser.
UserManager<ApplicationUser> UserManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
This works for me. I'm using Identity 2.0, it looks like GetApplicationUser isn't there anymore.
var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
if (!string.IsNullOrEmpty(form["FirstName"]))
{
user.FirstName = form["FirstName"];
}
if (!string.IsNullOrEmpty(form["LastName"]))
{
user.LastName = form["LastName"];
}
IdentityResult result = await UserManager.UpdateAsync(user);
I am using the new EF & Identity Core and I have the same issue, with the addition that I've got this error:
The instance of entity type cannot be tracked because another instance
of this type with the same key is already being tracked.
With the new DI model I added the constructor's Controller the context to the DB.
I tried to see what are the conflict with _conext.ChangeTracker.Entries() and adding AsNoTracking() to my calls without success.
I only need to change the state of my object (in this case Identity)
_context.Entry(user).State = EntityState.Modified;
var result = await _userManager.UpdateAsync(user);
And worked without create another store or object and mapping.
I hope someone else is useful my two cents.
Add the following code to your Startup.Auth.cs file under the static constructor:
UserManagerFactory = () => new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(PublicClientId, UserManagerFactory),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
AllowInsecureHttp = true
};
The UserManagerFactory setting line of code is what you use to associate your custom DataContext with the UserManager. Once you have done that, then you can get an instance of the UserManager in your ApiController and the UserManager.UpdateAsync(user) method will work because it is using your DataContext to save the extra properties you've added to your custom application user.
I am using .Net Core 3.1 or higher version.Please follow the solution:
public class UpdateAssignUserRole
{
public string username { get; set; }
public string rolename { get; set; }
public bool IsEdit { get; set; }
}
private async Task UpdateSeedUsers(UserManager<IdentityUser> userManager, UpdateAssignUserRole updateassignUsername)
{
IList<Users> Users = await FindByUserName(updateassignUsername.username);
if (await userManager.FindByNameAsync(updateassignUsername.username) != null)
{
var user = new IdentityUser
{
UserName = updateassignUsername.username,
Email = Users[0].Email,
};
var result = await userManager.FindByNameAsync(updateassignUsername.username);
if (result != null)
{
IdentityResult deletionResult = await userManager.RemoveFromRolesAsync(result, await userManager.GetRolesAsync(result));
if (deletionResult != null)
{
await userManager.AddToRoleAsync(result, updateassignUsername.rolename);
}
}
}
}

How to override IsInRole method in MVC 4 Custom Membership?

I'm very new to MVC. I'm doing a Custom Membership asp.net MVC4. Above are the Table & data i have created. I try to override isinrole method but its not working.Below is the sample code & i don't know where to edit it.
public override bool IsUserInRole(string userName, string roleName)
{
User user = repository.GetUser(userName);
Role role = repository.GetRole(roleName);
if (!repository.UserExists(user))
return false;
if (!repository.RoleExists(role))
return false;
return user.Name == role.Name;
}
Now i need to get list of roles for a user from UserInRole Table but the this table is not visible.I have to check whether the User role are matching with User.IsInRole("Administrator") .Hope anybody can guide me.Thank u in advance.
It's not working because you're comparing the role name with the user name ("a" != "Administrator"). You need something more like this.
public override bool IsUserInRole(string userName, string roleName)
{
User user = repository.GetUser(userName);
Role role = repository.GetRole(roleName);
if (!repository.UserExists(user))
return false;
if (!repository.RoleExists(role))
return false;
return user.Role.ID == role.ID;
}
It may differ depending on how your entities are setup though.

ASP MVC 3 Base controller for entity context access

I've implemented a base controller for my MVC 3 project to allow a common way of accessing a user entity from my db context :
public abstract class MyBaseController : Controller
{
protected DBEntitiesContainer db;
protected override void Initialize(System.Web.Routing.RequestContext requestContext)
{
base.Initialize(requestContext);
this.db = new DBEntitiesContainer();
}
public UserDetails GetActiveUserDetails()
{
UserDetails userDetails = GetObjects.GetActiveUserDetails(this.db);
return userDetails;
}
}
This works great and all my controllers have access to this.db.MyEntity and can retrieve a UserDetails object by calling this.GetActiveUserDetails()
However, the problem arises when I try to perform an update on the entity thus :
public class UpdateController : MyBaseController
{
public ActionResult Index()
{
UserDetails userDetails = this.GetActiveUserDetails();
userDetails.LastOnline = DateTime.Now;
UpdateModel(userDetails);
this.db.SaveChanges();
}
}
Any ideas why the UserDetails object is easily retrieved, but when I check my database after calling SaveChanges(), nothing has been updated ? I'm presuming I'm accessing my context in two different ways, but I can't see how I am...!
Edit: Here's the GetObjects.GetActiveUserDetails() method
public static UserDetails GetActiveUserDetails(DBEntitiesContainer db)
{
MembershipUser membershipUser = Membership.GetUser();
UserDetails userDetails;
try
{
if (membershipUser != null)
{
userDetails = (from u in db.UserDetails
where (u.UserId == (System.Guid)membershipUser.ProviderUserKey)
select u).First();
}
else
{
return GetGuestAccount();
}
}
catch
{
return GetGuestAccount();
}
return userDetails;
}
Not the cleanest method I know...
UpdateModel is helper method for Controller base class. it supports updating the properties of an object we pass it using the incoming form parameters during HttpPost action method.
It uses relfection to find out the property names of the object (Model object what we passed) and then automatically converts the assigns values to them based on the input values submitted by the form ( client form).
In your case you when u use update model it has no input value find associated model and it make the model default values as it is in database.
try to comment the updatemodel line and runt he code... it must work.
It's not a good idea to setup data access this way. One reason is that you should dispose of the db context after you use it. This means that using your method, this leaves the database connection open until garbage collection occurs, which could be minutes or hours later. As other web requests come in, new database connections are created, and again those are not disposed of either.. etc.. etc.. it's a pseudo-memory leak (not a true memory leak because it will eventually get collected, but it means resources are being used well after they are needed)

Resources