Don't make username unique asp.net identity - asp.net-mvc

I want to implement custom logic for username validation. Created function ValidateEntity for username custom validation but if I provide unique username while creating user then ValidateEntity function is hit and If I provide duplicate username then this function is not hit.
IdentityModel.cs
public class ApplicationUser : IdentityUser
{
public int AppId { get; set; }
//other attributes
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
return userIdentity;
}
}
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection", throwIfV1Schema: false)
{
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
protected override DbEntityValidationResult ValidateEntity(DbEntityEntry entityEntry, IDictionary<object, object> items)
{
if ((entityEntry != null) && (entityEntry.State == EntityState.Added))
{
var user = entityEntry.Entity as ApplicationUser;
//custom logic for username validation
}
return base.ValidateEntity(entityEntry, items);
}
}
In AccountController.cs
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
var result = await UserManager.CreateAsync(user, model.Password); //shouldn't it always goto ValidateEntity function?
if (result.Succeeded)
{
await SignInManager.SignInAsync(user, isPersistent:false, rememberBrowser:false);
return RedirectToAction("Index", "Home");
}
AddErrors(result);
}
return View(model);
}
Update:
I added public new string UserName { get; set; } and now I get error Name cannot be null or empty here is the screen shot of data.

It is not good practice for the username field not to be unique, unless you plan to cover that in your custom validator. However you should be able to override the username field in the ApplicationUser class:
public class ApplicationUser : IdentityUser
{
public int AppId { get; set; }
// Override username field
public new string UserName { get; set; }
//other attributes
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
return userIdentity;
}
}
Additionally, if your database already exists, you must also then remember to remove the unique index UserNameIndex for everything to work.

Related

how to save jwt token in databse asp .net 3.1 web api

I want to Save jwt token in the database I share the code of the controller where token generation is done but I don't know how to save the token or that code will work or nor
this is my controller where use jwt token
public class LoginController: Controller
{
private readonly JwtAuthContext _context;
private IConfiguration _config;
public LoginController(IConfiguration config, JwtAuthContext
context)
{
_config = config;
_context = context;
}
[Route("api/Register")]
[HttpPost]
public IActionResult Post([FromBody] Register register)
{
if (ModelState.IsValid)
{
_context.Add(register);
_context.SaveChanges();
}
Console.WriteLine(register);
var ttt = _context.Registers.ToList();
return Ok(new { result = ttt });
}
[HttpPost]
public IActionResult Login([FromBody] Login Login)
{
var user = Authenticate(Login);
if (user != null)
{
var token = Generate(user);
_context.SaveChanges();
return Ok(token);
}
return NotFound("User not found");
}
private string Generate(Register user)
{
var securityKey = new
SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:Key"]));
var credentials = new SigningCredentials(securityKey,
SecurityAlgorithms.HmacSha256);
var claims = new[]
{
new Claim(ClaimTypes.NameIdentifier, user.Email),
new Claim(ClaimTypes.Email, user.FullName),
new Claim(ClaimTypes.Role, user.Role)
};
var token = new JwtSecurityToken(_config["Jwt:Issuer"],
_config["Jwt:Audience"],
claims,
expires: DateTime.Now.AddMinutes(15),
signingCredentials: credentials);
return new JwtSecurityTokenHandler().WriteToken(token);
}
private Register Authenticate(Login Login)
{
var currentUser = _context.Registers.FirstOrDefault(o =>
o.Email.ToLower() == Login.Email.ToLower() && o.Password == Login.Password);
if (currentUser != null)
{
return currentUser;
}
return null;
}
this is my login model where I create a table of login
public class login{
public int LoginId{get;set;}
public string Email{get;set;}
public string Password{get;set;}
}
this is my register model where I can create a register model
public class Register{
public int Id{get;set;}
public string FullName{get;set;}
public string Email{get;set;}
public string Password{get;set;}
}
-------------
JwtAuthContext
--------------
public class JwtAuthContext : DbContext
{
public JwtAuthContext(DbContextOptions<JwtAuthContext> options)
: base(options)
{
}
public DbSet<Login> Logins { get; set; }
public DbSet<Register> Registers { get; set; }
public DbSet<AuthenticationToken> authenticationTokens { get;
set; }
}
This is my AuthenticationToken Model
public class AuthenticationToken
{
public string Token{get;set;}
}
Try this.
if (user != null)
{
var token = Generate(user);
_context.authenticationTokens.Add(token); // just add this line
_context.SaveChanges();
return Ok(token);
}

How to generate register url for other user

I want to make an application using .net core 5.0. users will register and login. Users who register and log in will create a reference url for other users, and I want to direct users who registered with this url to the registration page and write who produced the link. How can I do one and which library should I use? can you please help me?
controller
public IActionResult Register(string userReference = null)
{
ViewData["userReference"] = userReference;
return View();
}
public async Task<IActionResult> Register(RegisterViewModel model, string userReference)
{
if (ModelState.IsValid)
{
Random generator = new Random();
String autoRefCode = generator.Next(0, 1000000).ToString("D6");
if (userReference != null)
{
var userQuery = _context.Where(x => x.Reference = userReference); // other user ref
// code
}
var user = new User
{
UserName = model.Email,
Email = model.Email,
Name = model.Name,
Surname = model.Surname,
Reference = autoRefCode
};
var result = await _userManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await _userManager.AddToRoleAsync(user, "customer"); // role
await _signInManager.SignInAsync(user, isPersistent: false);
return RedirectToLocal(returnUrl);
}
}
return View(model);
}
private IActionResult RedirectToLocal(string returnUrl)
{
if (Url.IsLocalUrl(returnUrl))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction(nameof(HomeController.Index), "Home");
}
}
class
public class RegisterViewModel
{
public string Email { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public string Reference { get; set; }
}

mvc 5 code first userid as a Foreign Key - How to save data

Using MVC5 code first approach.
I haven't changed the user store, added a property called Name in ApplicationUser Class. So it looks like as follows : -
public class ApplicationUser : IdentityUser
{
[Required]
[StringLength(100)]
public string Name { get; set; }
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;
}
}
I have a company class, which looks like below :-
public class Company
{
public int Id { get; set; }
[Required]
[StringLength(255)]
public string Name { get; set; }
}
A company will definitely has more than one user, but in my design a user can be associated with more than one company. So I have a separate class for CompanyUsers which looks as follows :-
public class CompanyUsers
{
public int Id { get; set; }
[Required]
public virtual Company Company { get; set; }
[Required]
public virtual ApplicationUser User { get; set; }
}
Now, when I register a user, I'm setting its role and also companies that the user belongs to, but seems like the UserManager defined in the built-in code has already saved it. So after adding CompanyUsers data, when I call applicationDbContext.Savechanges() it fails as the user has already been saved in the database. Can you tell me how I can achieve it? I can do it in some other logic, like after creating a user, in a separate function assign users to company(s), but I want to know the solution in this circumstances. Also I can redesign the user store.
My modified register function in AccountController is as follows :-
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = model.Email, Email = model.Email, Name = model.Name };
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await UserManager.AddToRoleAsync(user.Id, model.Role);
var userCompany = new CompanyUsers
{
Company = _context.Companies.First(t => t.Id == model.CompanyId),
User = user
};
try
{
_context.CompanyUsers.Add(userCompany);
_context.SaveChanges();// throws exception
}
catch (DbEntityValidationException dbEx)
{
foreach (var validationErrors in dbEx.EntityValidationErrors)
{
foreach (var validationError in validationErrors.ValidationErrors)
{
Trace.TraceInformation("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage);
}
}
}
return RedirectToAction("UserViewAll", "Manage");
}
AddErrors(result);
}
// If we got this far, something failed, redisplay form
return View(model);
}
I have just started mvc code first approach, so I may not understand if you use technical jargon, thanks In Advance for your help!!!!!
Try adding the following code in the if (result.Succeeded) block:
_context.Entry(user).State = EntityState.Unchanged;
The issue appears to be that the data context in this method does not know the state of the user entity because UserManager.CreateAsync uses a separate context. The entity is attached when you assign it to the CompanyUser entity, and then this data context tries to save it as a new entity.

Error in adding custom table in user identity system

I was following this article to add my custom table.
http://www.itorian.com/2013/11/customizing-users-profile-to-add-new.html
In My AccountViewModels.cs, i have tried to add new custom table(UserProfileInfo) something like this---
public class ApplicationUser : IdentityUser
{
public string EmailID { get; set; }
public virtual UserProfileInfo UserProfileInfo { get; set; }
}
public class UserProfileInfo
{
public int Id { get; set; }
public string City { get; set; }
public string MobileNum { get; set; }
}
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection")
{
}
public System.Data.Entity.DbSet<UserProfileInfo> UserProfileInfo { get; set; }
}
}
and in my Account Controller's Register action (Post Version), i have tried to update register action like this but you can see in code at city and mobileNum,
its stating -----
xxx.RegisterViewModel' does not contain a definition for 'City' and no extension method 'City' accepting a first argument of type 'xxx.RegisterViewModel' could be found....
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser() { UserName = model.UserName, EmailID = model.EmailID,
UserProfileInfo = new UserProfileInfo
{ City = model.City,
MobileNum = model.ModileNum
}
};
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await SignInAsync(user, isPersistent: false);
return RedirectToAction("Index", "Home");
}
else
{
AddErrors(result);
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
i dont know what's happening here.plzz help me out.thanks in advance
I have seen that article as u mentioned.You will never be able to pass City and mobile number as parameter as u have not defined them in register view model.
If u simply want to just create and another table and wants to save that into database then u can do it like this-------
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser() { UserName = model.UserName };
user.HomeTown = model.HomeTown;
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await SignInAsync(user, isPersistent: false);
return RedirectToAction("Index", "Home");
}
else
{
AddErrors(result);
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
and change your Dbcontext to something like this----
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection")
{
}
public DbSet<UserProfileInfo> UserProfileInfo { get; set; }
}
and your Application user class should be something like this-----
public class ApplicationUser : IdentityUser
{
public string HomeTown { get; set; }
public virtual UserProfileInfo UserProfileInfo { get; set; }
}
You've created separated table - UserProfileInfo - that isn't part of ApplicationUser one.
What you've to do is:
crate new ApplicationUser
create new UserProfileInfo
link each other with proper navigation property or assign foreign keys manually (depending on your configuration)

AspNet.Identity Custom User and Custom Role should be simple; what am I missing?

Using examples from http://www.asp.net/identity I've gotten this far. The RoleManager works flawlessly and I treat the UserManager the same. I think everything is correct, but I can't seem to new up a UserManager correctly in a controller. What is wrong? At one point, I was successfully getting the UserManager to work but was getting an EntityValidationError saying "Id is required" when creating a new user with UserManager.Create(user, password); as posted in this question UserManager.Create(user, password) thowing EntityValidationError saying Id is required?
So after some time of hit and miss, I've created everything like the following but am getting a compile-time error on new ApplicationUserManager(new ApplicationUserStore(new MyAppDb())) saying:
The best overloaded method match for MyApp.Models.ApplicationUserManager.ApplicationUserManager(Microsoft.AspNet.Identity.IUserStore<MyApp.Models.ApplicationUser>)'
has some invalid arguments"
when trying to create the UserManager in my controller:
Here is the controller:
namespace MyApp.Controllers
{
[Authorize]
public class AccountController : BaseController
{
public AccountController()
: this(new ApplicationUserManager(new ApplicationUserStore(new MyAppDb())))
{
}
public AccountController(ApplicationUserManager userManager)
{
UserManager = userManager;
}
public ApplicationUserManager UserManager { get; private set; }
...
}
Here is the model:
namespace MyApp.Models
{
public class ApplicationUser : IdentityUser<string, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>
{
[Required]
[StringLength(50)]
public string FirstName { get; set; }
[Required]
[StringLength(50)]
public string LastName { get; set; }
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 ApplicationUserLogin : IdentityUserLogin<string>
{
}
public class ApplicationUserClaim : IdentityUserClaim<string>
{
}
public class ApplicationUserRole : IdentityUserRole<string>
{
}
public class ApplicationRole : IdentityRole<string, ApplicationUserRole>
{
[Required]
[StringLength(50)]
public string ProperName { get; set; }
[Required]
public string Description { get; set; }
}
public class MyAppDb : IdentityDbContext<ApplicationUser, ApplicationRole, string, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>
{
public MyAppDb()
: base("MyAppDb")
{
}
}
public class ApplicationUserManager : UserManager<ApplicationUser>
{
public ApplicationUserManager(IUserStore<ApplicationUser> store)
: base(store)
{
this.PasswordValidator = (IIdentityValidator<string>)new MinimumLengthValidator(8);
this.UserValidator = new UserValidator<ApplicationUser>(this) { AllowOnlyAlphanumericUserNames = false, RequireUniqueEmail = true };
}
}
public class ApplicationUserStore : UserStore<ApplicationUser, ApplicationRole, string, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>
{
public ApplicationUserStore(MyAppDb context)
: base(context)
{
}
public override async Task CreateAsync(ApplicationUser user)
{
await base.CreateAsync(user);
}
}
public class ApplicationRoleStore : RoleStore<ApplicationRole, string, ApplicationUserRole>
{
public ApplicationRoleStore(MyAppDb context)
: base(context)
{
}
}
public class ApplicationRoleManager : RoleManager<ApplicationRole>
{
public ApplicationRoleManager(IRoleStore<ApplicationRole, string> store)
: base(store)
{
}
}
}
UPDATE: I can get the error to go away on the creation of the UserManager by changing this:
public class ApplicationUserManager : UserManager<ApplicationUser>
{
public ApplicationUserManager(IUserStore<ApplicationUser> store)
: base(store)
{
this.PasswordValidator = (IIdentityValidator<string>)new MinimumLengthValidator(8);
this.UserValidator = new UserValidator<ApplicationUser>(this) { AllowOnlyAlphanumericUserNames = false, RequireUniqueEmail = true };
}
}
to this:
public class ApplicationUserManager : UserManager<ApplicationUser>
{
public ApplicationUserManager(IUserStore<ApplicationUser, string> store)
: base(store)
{
this.PasswordValidator = (IIdentityValidator<string>)new MinimumLengthValidator(8);
this.UserValidator = new UserValidator<ApplicationUser>(this) { AllowOnlyAlphanumericUserNames = false, RequireUniqueEmail = true };
}
}
notice I just added , string, but it then puts the error "The best overloaded method match for "Microsoft.AspNet.Identity.UserMaager<MyApp.Models.ApplicaitonUser>.UserManager(Microsoft.AspNet.Identity.IUserStore<MyApp.Models.ApplicationUser>)' has some invalid arguments" on base(store).
UPDATE 2: I changed this:
public class ApplicationUserManager : UserManager<ApplicationUser>
{
public ApplicationUserManager(IUserStore<ApplicationUser, string> store)
...
}
to this:
public class ApplicationUserManager : UserManager<ApplicationUser, string>
{
public ApplicationUserManager(IUserStore<ApplicationUser, string> store)
...
}
Notice the ' string in public class ApplicationUserManager : UserManager<ApplicationUser, string>. But now, guess what? You guessed it--back to this issue: UserManager.Create(user, password) thowing EntityValidationError saying Id is required?
What am I missing?
Try this way. I had the same issue, you need to provide the id.
//
// POST: /Account/Register
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser() {
UserName = model.UserName,
Id = Guid.NewGuid().ToString(),
Created = DateTime.Now,
LastLogin = null
};
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await SignInAsync(user, isPersistent: false);
return RedirectToAction("Index", "Home");
}
else
{
AddErrors(result);
}
}
// If we got this far, something failed, redisplay form
return View(model);
}

Resources