We are implementing identityserver authentication for our .net core api project. I have implemented identityserver infrastructure which created AspNetUsers,AspNetUserRoles etc. tables. The users are inserted in aspnetusers table. I want to use our member table instead of aspnetusers table. How can I do that?
public class ApplicationUser : IdentityUser
{
[Required]
[MaxLength(200)]
public String Name { get; set; }
}
[HttpPost]
[Route("token")]
public async Task<IActionResult> CreateToken([FromBody] LoginModel loginModel)
{
if (ModelState.IsValid)
{
var loginResult = await signInManager.PasswordSignInAsync(loginModel.Username, loginModel.Password, isPersistent: false, lockoutOnFailure: false);
if (!loginResult.Succeeded)
{
return BadRequest();
}
var user = await userManager.FindByNameAsync(loginModel.Username);
Login();
return Ok(GetToken(user));
}
return BadRequest(ModelState);
}
Related
I have a project in which users can have multiple roles, such as cashier and stock clerk. These roles have the same rights, however someone can also have the roles admin and cashier. In this case he can access more features than a admin/cashier on its own.
I've searched far and wide but I don't get any wiser from the documentation, as I first thought policies were the way to go, but now I think we need claim-based authorization.
After searching and playing around I found no answers on the following questions:
What tables/entities do I need?
Can this be done without scaffolding tools?
How does this whole process work, how does .NET CORE know what roles to look at? How can I use custom roles?
If someone could help me out with this I would appreciate it.
Cheers.
One way is to use Identity and authorize the user by using [Authorize(Roles ="Admin")].
If you want to do without scaffolding tools,you could use jwt token authentication or cookie authentication.
Here is a simple demo about how to use cookie authentication:
Model:
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public string Password { get; set; }
public List<UserRole> UserRoles { get; set; }
}
public class Role
{
public int Id { get; set; }
public string RoleName { get; set; }
public List<UserRole> UserRoles { get; set; }
}
public class UserRole
{
public int UserId { get; set; }
public User User { get; set; }
public int RoleId { get; set; }
public Role Role { get; set; }
}
public class LoginModel
{
public string Name { get; set; }
public string Password { get; set; }
}
Controller:
public class HomeController : Controller
{
private readonly YouDbContext _context;
public HomeController(YouDbContext context)
{
_context = context;
}
public IActionResult Login()
{
return View();
}
[HttpPost]
public async Task<IActionResult> Login(LoginModel model)
{
var claims = new List<Claim>{};
var user = _context.User
.Include(u=>u.UserRoles)
.ThenInclude(ur=>ur.Role)
.Where(m => m.Name == model.Name).FirstOrDefault();
if(user.Password==model.Password)
{
foreach(var role in user.UserRoles.Select(a=>a.Role.RoleName))
{
var claim = new Claim(ClaimTypes.Role, role);
claims.Add(claim);
}
var claimsIdentity = new ClaimsIdentity(
claims, CookieAuthenticationDefaults.AuthenticationScheme);
var authProperties = new AuthenticationProperties{};
await HttpContext.SignInAsync(
CookieAuthenticationDefaults.AuthenticationScheme,
new ClaimsPrincipal(claimsIdentity),
authProperties);
}
return View("Index");
}
public IActionResult Index()
{
return View();
}
//allow Cashier
[Authorize(Roles = "Cashier")]
public IActionResult Privacy()
{
return View();
}
//allow Admin
[Authorize(Roles = "Admin")]
public IActionResult AllowAdmin()
{
return View();
}
//allow both of the Admin and Cashier
[Authorize(Roles = "Admin,Cashier")]
public IActionResult AllowBoth()
{
return View();
}
//user has no rights to access the page
public IActionResult AccessDenied()
{
return View();
}
//log out
public async Task<IActionResult> Logout()
{
await HttpContext.SignOutAsync(
CookieAuthenticationDefaults.AuthenticationScheme);
return RedirectToAction("Index");
}
}
DbContext:
public class YouDbContext: DbContext
{
public YouDbContext(DbContextOptions<YouDbContext> options)
: base(options)
{
}
public DbSet<User> User { get; set; }
public DbSet<Role> Role { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<UserRole>()
.HasKey(bc => new { bc.UserId, bc.RoleId });
modelBuilder.Entity<UserRole>()
.HasOne(bc => bc.User)
.WithMany(b => b.UserRoles)
.HasForeignKey(bc => bc.UserId);
modelBuilder.Entity<UserRole>()
.HasOne(bc => bc.Role)
.WithMany(c => c.UserRoles)
.HasForeignKey(bc => bc.RoleId);
}
}
Startup.cs:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options =>
{
options.LoginPath = "/Home/Login";
options.AccessDeniedPath = "/Home/AccessDenied";
});
services.AddDbContext<WebApplication1Context>(options =>
options.UseSqlServer(Configuration.GetConnectionString("WebApplication1Context")));
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
}
Result:
I'm Working on a project that had authorization implemented with One user has One role.
Now we want to convert that relation to many to many but in the asp.net core authorization it went wrong.
[Serializable]
public class User
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Required]
public Guid? Id { get; set; }
public virtual IList<UserRole> UserRoles { get; set; } = new List<UserRole>();
[NotMapped]
public string Token { get; set; }
/**/
[Serializable]
public class UserRole
{
public Guid UserId { get; set; }
public User User { get; set; }
public int RoleId { get; set; }
public Role Role { get; set; }
}
[Serializable]
public class Role
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[JsonIgnore]
public int Id { get; set; }
public string Name { get; set; }
}
}
while our database and mapping works perfect. the authorization in asp.net core fails.
autorization service:
public async Task<DTO_User> Authenticate(string username, string password)
{
var users = await _userRepo.GetAll();
var user = users.Where(u => u.Username == (username) && u.Password == (password)).FirstOrDefault();
if (user == null)
return null;
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(_appSettings.Secret);
var tokenDescriptor = new SecurityTokenDescriptor
{
Expires = DateTime.UtcNow.AddDays(1),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key),
SecurityAlgorithms.HmacSha256Signature)
};
var claims = new List<Claim>
{
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
new Claim(ClaimTypes.Name, user.Username.ToString()),
};
var roles = await this._userRepo.GetUserRoles(user.Id.Value.ToString());
var claimsWithRoles = roles.ToList().Select(role => new Claim(ClaimTypes.Role, role.Name));
var allClaims = claims.Concat(claimsWithRoles);
tokenDescriptor.Subject = new ClaimsIdentity(allClaims);
var token = tokenHandler.CreateToken(tokenDescriptor);
user.Token = tokenHandler.WriteToken(token);
// remove password before returning
user.Password = null;
return _mapper.Map<DTO_User>(user);
}
**Controller**
[Route("api/[controller]")]
[ApiController]
[Authorize]
[EnableCors("CorsPolicy")]
public class SessionController : ControllerBase
{
[HttpGet]
[Route("active")]
public async Task<IActionResult> GetAllActive()
{
}
}
}
but where getting the exception:
I wants to create a new user with role. I'm using entity migration. so i get the all default tables. Without roles I'm able to register a new user but when i add the roles drop down I'm facing a error Cannot convert from string to ourproject.entitites.user
Please help and teach me where i did the mistake. I'm new to .net core technology.
I'm facing a problem with user.Id
await _userManager.AddToRoleAsync(user.Id, model.UserRoles);
ControllerCode:
[HttpPost, ValidateAntiForgeryToken]
public async Task<IActionResult> Register(RegisterUserModel model)
{
if (ModelState.IsValid)
{
var user = new User { UserName = model.Username, Email = model.Email,
PhoneNumber = model.PhoneNumber };
//var phoneNo = new User { PhoneNumber = model.PhoneNumber };
var createResult = await _userManager.CreateAsync(user, model.Password);
if (createResult.Succeeded)
{
await _userManager.AddToRoleAsync(user.Id, model.UserRoles);
return RedirectToAction("Details", "Home");
}
else
{
ViewBag.Name = new SelectList(_Context.Roles.Where(u => !u.Name.Contains("Admin"))
.ToList(), "Name", "Name");
foreach (var error in createResult.Errors)
{
ModelState.AddModelError("", error.Description);
}
}
}
return View();
}
Registermodel Code:
public class RegisterUserModel
{
[Required,MaxLength(256)]
public string Username { get; set; }
[Required, DataType(DataType.Password)]
public string Password { get; set; }
[Required, DataType(DataType.Password), Compare(nameof(Password))]
public string ConfirmPassword { get; set; }
[Required, DataType(DataType.EmailAddress),MaxLength(256)]
public string Email { get; set; }
[Required,DataType(DataType.PhoneNumber)]
public string PhoneNumber { get; set; }
[Display(Name ="UserRoles")]
public string UserRoles { get; set; }
}
User Entity Code:
using Microsoft.AspNetCore.Identity;
namespace OurProject.Entities
{
public class User : IdentityUser
{
}
}
Here is a functional code for .net core 2.0. In AddToRoleAsync method I am sending user object itself.
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Register(RegisterViewModel model, string returnUrl = null)
{
ViewData["ReturnUrl"] = returnUrl;
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
var result = await _userManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
string roleName = "Manager";
var isExistRole = await this._roleManager.RoleExistsAsync(roleName);
if (!isExistRole)
{
await this._roleManager.CreateAsync(
new IdentityRole
{
Id = Guid.NewGuid().ToString(),
Name = roleName
});
}
await _userManager.AddToRoleAsync(user, roleName);
return RedirectToLocal(returnUrl);
}
AddErrors(result);
}
// If we got this far, something failed, redisplay form
return View(model);
}
I'm attempting to extend the ASP.NET Identity. I feel like I have most of the parts. The model and user objects all properly populate. However, when I check the database for the new record inserted via the CreateAsync function, the new fields are all NULL. What am I missing?
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Register(RegisterViewModel model, string returnUrl = null)
{
ViewData["ReturnUrl"] = returnUrl;
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = model.Email, Email = model.Email, FirstName = model.FirstName, LastName = model.LastName
, Organization = model.Organization };
var result = await _userManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
_logger.LogInformation("User created a new account with password.");
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
var callbackUrl = Url.EmailConfirmationLink(user.Id.ToString(), code, Request.Scheme);
await _emailSender.SendEmailConfirmationAsync(model.Email, callbackUrl);
await _signInManager.SignInAsync(user, isPersistent: false);
_logger.LogInformation("User created a new account with password.");
return RedirectToLocal(returnUrl);
}
AddErrors(result);
}
// If we got this far, something failed, redisplay form
return View(model);
}
services.AddIdentity<ApplicationUser, IdentityRole>(options =>
{
// Signin settings
options.SignIn.RequireConfirmedEmail = false;
options.SignIn.RequireConfirmedPhoneNumber = false;
})
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
public class ApplicationUser : IdentityUser
{
public String FirstName;
public String LastName;
public String Organization;
}
You need to use auto-implemented properties in your ApplicationUser class instead of just using public fields. That might be the problem.
public class ApplicationUser : IdentityUser
{
public String FirstName { get; set; }
public String LastName { get; set; }
public String Organization { get; set; }
}
I have created web api 2 project which created a local db in which there was a table "AspNetUser". I have merged those tables with my own db. In my database I have a table "Employee Information" that will store all information of the employee except his Email,Password and UserName and all the other information will be stored in "Employee Information" table.
This is the pre-written code to register user:
[AllowAnonymous]
[Route("Register")]
public async Task<IHttpActionResult> Register(RegisterBindingModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var user = new ApplicationUser() { UserName = model.UserName, Email = model.Email};
IdentityResult result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
var currentUser = UserManager.FindByName(user.UserName);
var roleresult = UserManager.AddToRole(currentUser.Id, model.SelectedRole);
}
else if (!result.Succeeded)
{
return GetErrorResult(result);
}
return Ok();
}
And This is my own logic to register User:
[ResponseType(typeof(EmployeeInformation))]
[ActionName("EmployeeInfo")]
[DeflateCompression]
public IHttpActionResult PostEmployeeInformation(EmployeeInformation EmployeeInfo)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.EmployeeInformations.Add(EmployeeInfo);
db.SaveChanges();
So how can I Store Email,password and Username in "AspNetUser" table and all the other information(name,fathername,dob etc) in "EmployeeInformation" table.
Thanks.
Simply add relation between ApplicationUser and EmployeeInformation entities:
public class ApplicationUser: IdentityUser
{
// other properties
public int EmployeeInformationID {get;set;}
public virtual EmployeeInformation EmployeeInformation {get;set;}
}
Do same for EmployeeInformation class
public class EmployeeInformation
{
// other properties
public string UserID {get;set;}
public virtual ApplicationUser User {get;set;}
}
Now you have seprate class for user's extra information for example you could write:
public IHttpActionResult PostEmployeeInformation(EmployeeInformation employeeInfo)
{
employeeInfo.UserID="your desired user id, current user id for example";
db.EmployeeInformations.Add(employeeInfo);
db.SaveChanges();
}