the issue was actually coming from the fact that, at first, my web app was using .net core 1.1, which deploys all the DLL in the "wwwroot" folder of the web application. However, with asp.net core 2.0, it does not do that anymore as the DLL are picked up from a global store. However, as Visual Studio does not clean the destination folder before a publish, I ended up with a situation where the 1.1 DLL were in my wwwroot, so the web site was picking up these ones instead of the 2.0 ones in the store folder.
This is explained in more details here: https://github.com/Azure/app-service-announcements-discussions/issues/2#issuecomment-313816550
Solution with _userManager.AddClaimsAsync
. Here is the simplified version of changes I made under ConfigureServices:
services.AddAuthorization(options => {
options.AddPolicy("CRM", policy => { policy.RequireClaim("department", "Sales", "Customer Service", "Marketing", "Advertising", "MIS"); });
});
AccountController constructor:
private readonly UserManager<ApplicationUser> _userManager;
private readonly SignInManager<ApplicationUser> _signInManager;
private readonly IEmailSender _emailSender;
private readonly ILogger _logger;
private readonly MyDB_Context _context;
public AccountController(
MyDB_Context context,
UserManager<ApplicationUser> userManager,
SignInManager<ApplicationUser> signInManager,
IEmailSender emailSender,
ILogger<AccountController> logger)
{
_context = context;
_userManager = userManager;
_signInManager = signInManager;
_emailSender = emailSender;
_logger = logger;
}
Under LogIn:
(var vUser is my own class with properties Name, department, SingIn, etc...). The sample below uses combination of custom user table mytable (to read from claim types and their values) and AspNetUserClaims table (to add claims):
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)
{
ViewData["ReturnUrl"] = returnUrl;
if (ModelState.IsValid) {
var vUser = _context.mytable.SingleOrDefault(m => m.Email.ToUpper() == model.Email.ToUpper());
const string Issuer = "https://www.mycompany.com/";
var user = _userManager.Users.Where(u => u.Email == model.Email).FirstOrDefault();
ApplicationUser applicationUser = await _userManager.FindByNameAsync(user.UserName);
IList<Claim> allClaims = await _userManager.GetClaimsAsync(applicationUser); // get all the user claims
// Add claim if missing
if (allClaims.Where(c => c.Type == "department" && c.Value == vUser.department).ToList().Count == 0) {
await _userManager.AddClaimAsync(user, new Claim("department", vUser.department, ClaimValueTypes.String, Issuer));
}
// Remove all other claim values for "department" type
var dept = allClaims.Where(c => c.Type == "department" && c.Value != vUser.department);
foreach(var claim in dept) {
await _userManager.RemoveClaimAsync(user, new Claim("department", claim.Value, ClaimValueTypes.String, Issuer));
}
vUser.SignIn = DateTime.Now; _context.Update(vUser); await _context.SaveChangesAsync();
// This doesn't count login failures towards account lockout
// To enable password failures to trigger account lockout, set lockoutOnFailure: true
var result = await _signInManager.PasswordSignInAsync(vUser.Name, model.Password, model.RememberMe, lockoutOnFailure: false);
//var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, lockoutOnFailure: false);
if (result.Succeeded) {
_logger.LogInformation("User logged in.");
return RedirectToLocal(returnUrl);
}
if (result.RequiresTwoFactor) {
return RedirectToAction(nameof(LoginWith2fa), new { returnUrl, model.RememberMe });
}
if (result.IsLockedOut) {
_logger.LogWarning("User account locked out.");
return RedirectToAction(nameof(Lockout));
} else {
ModelState.AddModelError(string.Empty, "Invalid login attempt.");
return View(model);
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
This is what I have in my controller:
[Authorize(Policy = "CRM")]
public class CRMController : Controller
Best Answer
I've just followed this article and everything goes perfect.
Migrating Authentication and Identity to ASP.NET Core 2.0
Hope it helps other.
TG.