I created a new MVC5 project with Identity and it makes its own db which i want to change with same one but mine and on cloud server. so i have 2 connection stings and the only things that i changed was table names ex: aspnetUser to CJUser and so on. I want some simple way of changing auto generated local db to my own cloud one.
2 connection strings i have are
default one which Identity creates and
my own db which i connected.
So project works with its own connection but when i change connections in Identity models to mine, it stops working.
public class ApplicationUser : IdentityUser
{
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
return userIdentity;
}
}
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("IdentityDbContext", throwIfV1Schema: false)
{
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
}
Try to use Automatic migration
Related
I am using AspNet.Identity for User Management in my MVC project because I believe it is a great start, now that I have it working (with little changes), I wanted to add an Audit Trail (Track Changes) like my other DbContext that I use.
In IdentityModel.cs, I have the following code that works, but only in certain situations:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection", throwIfV1Schema: false)
{
//Can't recall if this was there by default
Configuration.AutoDetectChangesEnabled = true;
}
public override int SaveChanges()
{
//Tell EF to Track Changes
ChangeTracker.DetectChanges();
//More code once I get this working
//
}
}
In my Controller, I have the following:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Edit(EditUserViewModel editUser)
{
var user = await UserManager.FindByIdAsync(editUser.Id);
//Update a property within the User object
user.FirstName = "Updated First Name";
//Save to database
var result = UserManager.Update(user);
//The above saves to database, but doesn't trigger SaveChanges()
//SaveChanges() will be triggered if I call
HttpContext.GetOwinContext().Get<ApplicationDbContext>().SaveChanges();
}
When the above HttpContext.GetOwinContext().Get<ApplicationDbContext>().SaveChanges(); is called, the updated ApplicationUser has an EntityState of Unchanged. Makes sense as it was already saved.
However, I am trying to see how I can utilize the UserManager and still work with SaveChanges().
I also understand that I could write a class that would log all of this myself, but as I expand the ApplicationUser (or ApplicationRole) I would like to avoid the extra coding for the Audit Log.
Any advice or links would help!
Set AutoSaveChanges to false in the constructor of your UserStore (which you would pass to the constructor of the UserManager).
public class MyUserStore : UserStore<User, Role, int, UserLogin, UserRole, UserClaim>
{
private MyDbContext _context;
public MyUserStore(MyDbContext context) : base(context)
{
//Set this to false
AutoSaveChanges = false;
_context = context;
}
}
Now you can call save changes as you normally would and the change tracker will contain the changes you're expecting.
I did however encounter an OptimisticConcurrencyException when I tried to make more than one call to UserManager between calls to SaveChanges. I just called SaveChanges after each UserManager operation.
My current code in as following.
public class ApplicationUser : IdentityUser
{
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
return userIdentity;
}
}
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection", throwIfV1Schema: false)
{
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
I Want to add sum more properties in ApplicationUser class so that these fields available on views like
#User.Identity.FullName
My login action is placed at here
To be able to get it the way:
1 - You need to create a Claim for that user
HttpContext.Current.GetOwinContext().GetUserManager<UserManager>().AddClaimsAsync(UserId, new Claim("FullName", "The value for the full name"));
2 - Once you add the claim for the user you can use this. I made this extension class so I would be able to get the claim value in the view.
public static class IdentityExtensions
{
public static string FullName(this IIdentity identity)
{
return ((ClaimsIdentity)identity).FindFirst("FullName")?.Value;
}
}
With this you can call it like #User.Identity.FullName()
I'm placing an [Authorize(Users = "user#sample.com")] attribute at the top of my Controller:
[Authorize(Users = #"user#sample.com")]
public class PostsController : ApiController
{
... methods...
}
The user's usernames are the email address. When I sign in with user#sample.com I still get a 401 Unauthorized this controller's methods.
I've also notice that, even after the user signs in both System.Web.HttpContext.Current.User.Identity.Name and System.Security.Claims.ClaimsPrincipal.Current.Identity.Name are null.
These are a few related classes:
ApplicationUser.cs
public class ApplicationUser : IdentityUser
{
public string Hometown { get; set; }
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager, string authenticationType)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, authenticationType);
// Add custom user claims here
return userIdentity;
}
}
ApplicationDbContext
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("MyProjectEntitiesIdentity", throwIfV1Schema: false)
{
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
The issue happens on my local dev instance as well as on the hosted site.
I know this is very vague, I just don't know what other issues may be relevant here. So, please ask for more information and I will update the post.
I need to create a Web API C# application for an existing MySQL database. I've managed to use Entity Framework 6 to bind every database table to a RESTful API (that allows CRUD operations).
I want to implement a login/registration system (so that I can implement roles and permissions in the future, and restrict certain API requests).
The MySQL database I have to use has a table for users (called user) that has the following self-explanatory columns:
id
email
username
password_hash
It seems that the de-facto standard for authentication is ASP.Net Identity. I have spent the last hour trying to figure out how to make Identity work with an existing DB-First Entity Framework setup.
If I try to construct ApplicationUser instances storing user instances (entities from the MySQL database) to retrieve user data, I get the following error:
The entity type ApplicationUser is not part of the model for the current context.
I assume I need to store Identity data in my MySQL database, but couldn't find any resource on how to do that. I've tried completely removing the ApplicationUser class and making my user entity class derive from IdentityUser, but calling UserManager.CreateAsync resulted in LINQ to Entities conversion errors.
How do I setup authentication in a Web API 2 application, having an existing user entity?
You say:
I want to implement a login/registration system (so that I can
implement roles and permissions in the future, and restrict certain
API requests).
How do I setup authentication in a Web API 2 application, having an
existing user entity?
It definitely means that you DO NOT need ASP.NET Identity. ASP.NET Identity is a technology to handle all users stuffs. It actually does not "make" the authentication mechanism. ASP.NET Identity uses OWIN Authentication mechanism, which is another thing.
What you are looking for is not "how to use ASP.NET Identity with my existing Users table", but "How to configure OWIN Authentication using my existing Users table"
To use OWIN Auth follow these steps:
Install the packages:
Owin
Microsoft.AspNet.Cors
Microsoft.AspNet.WebApi.Client
Microsoft.AspNet.WebApi.Core
Microsoft.AspNet.WebApi.Owin
Microsoft.AspNet.WebApi.WebHost
Microsoft.Owin
Microsoft.Owin.Cors
Microsoft.Owin.Host.SystemWeb
Microsoft.Owin.Security
Microsoft.Owin.Security.OAuth
Create Startup.cs file inside the root folder (example):
make sure that [assembly: OwinStartup] is correctly configured
[assembly: OwinStartup(typeof(YourProject.Startup))]
namespace YourProject
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
var config = new HttpConfiguration();
//other configurations
ConfigureOAuth(app);
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseWebApi(config);
}
public void ConfigureOAuth(IAppBuilder app)
{
var oAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/api/security/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromHours(2),
Provider = new AuthorizationServerProvider()
};
app.UseOAuthAuthorizationServer(oAuthServerOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
}
}
public class AuthorizationServerProvider : OAuthAuthorizationServerProvider
{
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
context.Validated();
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
try
{
//retrieve your user from database. ex:
var user = await userService.Authenticate(context.UserName, context.Password);
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
identity.AddClaim(new Claim(ClaimTypes.Name, user.Name));
identity.AddClaim(new Claim(ClaimTypes.Email, user.Email));
//roles example
var rolesTechnicalNamesUser = new List<string>();
if (user.Roles != null)
{
rolesTechnicalNamesUser = user.Roles.Select(x => x.TechnicalName).ToList();
foreach (var role in user.Roles)
identity.AddClaim(new Claim(ClaimTypes.Role, role.TechnicalName));
}
var principal = new GenericPrincipal(identity, rolesTechnicalNamesUser.ToArray());
Thread.CurrentPrincipal = principal;
context.Validated(identity);
}
catch (Exception ex)
{
context.SetError("invalid_grant", "message");
}
}
}
}
Use the [Authorize] attribute to authorize the actions.
Call api/security/token with GrantType, UserName, and Password to get the bearer token. Like this:
"grant_type=password&username=" + username + "&password=" password;
Send the token within the HttpHeader Authorization as Bearer "YOURTOKENHERE". Like this:
headers: { 'Authorization': 'Bearer ' + token }
Hope it helps!
Since your DB schema are not compatible with default UserStore You must implement your own UserStore and UserPasswordStore classes then inject them to UserManager. Consider this simple example:
First write your custom user class and implement IUser interface:
class User:IUser<int>
{
public int ID {get;set;}
public string Username{get;set;}
public string Password_hash {get;set;}
// some other properties
}
Now author your custom UserStore and IUserPasswordStore class like this:
public class MyUserStore : IUserStore<User>, IUserPasswordStore<User>
{
private readonly MyDbContext _context;
public MyUserStore(MyDbContext context)
{
_context=context;
}
public Task CreateAsync(AppUser user)
{
// implement your desired logic such as
// _context.Users.Add(user);
}
public Task DeleteAsync(AppUser user)
{
// implement your desired logic
}
public Task<AppUser> FindByIdAsync(string userId)
{
// implement your desired logic
}
public Task<AppUser> FindByNameAsync(string userName)
{
// implement your desired logic
}
public Task UpdateAsync(AppUser user)
{
// implement your desired logic
}
public void Dispose()
{
// implement your desired logic
}
// Following 3 methods are needed for IUserPasswordStore
public Task<string> GetPasswordHashAsync(AppUser user)
{
// something like this:
return Task.FromResult(user.Password_hash);
}
public Task<bool> HasPasswordAsync(AppUser user)
{
return Task.FromResult(user.Password_hash != null);
}
public Task SetPasswordHashAsync(AppUser user, string passwordHash)
{
user.Password_hash = passwordHash;
return Task.FromResult(0);
}
}
Now you have very own user store simply inject it to the user manager:
public class ApplicationUserManager: UserManager<User, int>
{
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
{
var manager = new ApplicationUserManager(new MyUserStore(context.Get<MyDbContext>()));
// rest of code
}
}
Also please note you must directly inherit your DB Context class from DbContext not IdentityDbContext since you have implemented own user store.
I have Solution consisting of 3 projects, first is Data Access Layer (where models and Database Context are defined), and other two are Asp.net MVC 5 and Asp.net Web Api 2 projects.
For authentication and authorization I'm using Asp.net Identity which I've set up like this (in my DAL project):
public class DatabaseContext : IdentityDbContext<User>
{
public DatabaseContext()
: base("DefaultConnection")
{
Configuration.LazyLoadingEnabled = true;
}
public DbSet<IdentityUser> IdentityUsers { get; set; }
/*
Other DbSets ...
*/
}
My User class extends IdentityUser.
In my ASP.net project I've changed a bit Account controller so it works with my Database Context, here are relevant parts which I changed:
[Authorize]
public class AccountController : Controller
{
public AccountController()
: this(new UserManager<User>(new UserStore<User>(new DatabaseContext())))
{
}
public AccountController(UserManager<User> userManager)
{
UserManager = userManager;
}
public UserManager<User> UserManager { get; private set; }
}
And this part works fine. So my question is, what changes I have to do in order my Web API project works with my entity User and my Database Context, so in order to consume API user must be logged in ? (and of-course user has option to register via API).
I.E. I want to enable authorization and authentication for web api 2 by using my Database Context and class User which extends Identity User class.
UPDATE
What I've tried to do is this: I've replaced all IdentityUser classes in my web api 2 project with my class User, but on line (when I try to log in):
User user = await userManager.FindAsync(context.UserName, context.Password);
I get error:
System.Data.SqlClient.SqlException: Invalid object name 'dbo.AspNetUsers'.
This approach worked for my asp.net MVC project.
In short what I did was:
In my DatabaseContext class I've added these lines:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<IdentityUser>()
.ToTable("AspNetUsers");
modelBuilder.Entity<User>()
.ToTable("AspNetUsers");
}
In asp.net web api project I've changed all classes IdentityUser to User, and that's it