public class ApplicationUser : IdentityUser<string, IdentityUserLogin, IdentityUserRole, ApplicationUserClaim> {...}
Here is the default definition of ApplicationUser for comparison:
public class ApplicationUser : IdentityUser {...}
public class IdentityUser : IdentityUser<string, IdentityUserLogin, IdentityUserRole, IdentityUserClaim>, IUser, IUser<string>
I had to override the definition of IdentityUser because I added a property to IdentityUserClaim.
public class ApplicationUserClaim : IdentityUserClaim<string>
{
public string Issuer { get; set; }
}
public class ApplicationDbContext : IdentityDbContext<ApplicationUser, ApplicationRole, string, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>
{
public ApplicationDbContext(string connectionNameOrString) : base(connectionNameOrString)
{
//Keep EF from trying to track this
Database.SetInitializer<ApplicationDbContext>(null);
}
public ApplicationDbContext() : this("SecurityContext"){}
public IDbSet<ApplicationUserClaim> Claims { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new ApplicationUserConfiguration()); modelBuilder.Configurations.Add(new IdentityRoleConfiguration()); modelBuilder.Configurations.Add(new IdentityUserRoleConfiguration()); modelBuilder.Configurations.Add(new IdentityUserLoginConfiguration()); modelBuilder.Configurations.Add(new ApplicationUserClaimConfiguration()); }
public static ApplicationDbContext Create()
{
return new ApplicationDbContext("SecurityContext");
}
I use the issuer property in ApplicationUserClaim for storing the clientId that claims belong to, as some users can belong to multiple clients, with different permissions in each.
ApplicationDbContext is where you will do your Entity Framework mappings to your legacy tables. I created a number of views to abstract this away from the base tables that the application used, mainly to deal with translating page level permissions in the application into claims. Here is the EntityTypeConfiguration for ApplicationUserClaim, the others are done similarly.
public class ApplicationUserClaimConfiguration : EntityTypeConfiguration<ApplicationUserClaim>
{
/// <summary>
/// Claims returned from this query will be stored in the application auth cookie
/// </summary>
public ApplicationUserClaimConfiguration()
{
ToTable("vwUserClaims");
Property(c => c.UserId).HasColumnName("entityContactId");
}
}
Application claims are not by default stored in the application cookie, and are not even the same class as claims that are stored in the application cookie, so if you want to store your application claims in the application cookie you will need to translate between your application claims class and the System.Security.Claims.Claim class. This is done in the ApplicationUserStore in the GetClaimsAsync method, shown below.
public class ApplicationUserStore : UserStore<ApplicationUser, IdentityRole, string, IdentityUserLogin, IdentityUserRole, ApplicationUserClaim>
{
private ApplicationDbContext myContext;
private ILog log = LogManager.GetLogger(typeof (ApplicationUserStore));
public ApplicationUserStore(ApplicationDbContext context) : base(context)
{
myContext = context;
}
/// <summary>
/// this is where we could translate any custom properties on the <see cref="ApplicationUserClaim"/> to something on the <see cref="Claim"/>
/// </summary>
/// <param name="user"></param>
/// <returns></returns>
public override Task<IList<Claim>> GetClaimsAsync(ApplicationUser user)
{
log.Debug("Getting Claims");
var appClaims = myContext.Claims.Where(c => c.UserId == user.Id).ToList();
//be careful turning this on, there can be a lot of claims and logging them all can impact performance
appClaims.ForEach(c=>log.Verbose(c.ToString()));
return Task.FromResult<IList<Claim>>(appClaims.Where(c=>c.ClaimValue!=null).Select(c => new Claim(c.ClaimType, c.ClaimValue, null, c.Issuer)).ToList());
}
public override async Task UpdateAsync(ApplicationUser user)
{
//We don't allow any updates except to password
log.DebugFormat("trying to update user {0}", user.Id);
//await base.UpdateAsync(user);
}
public override Task SetPasswordHashAsync(ApplicationUser user, string passwordHash)
{
return base.SetPasswordHashAsync(user, passwordHash);
}
}
No comments:
Post a Comment