I recently implemented a feature set based on claims in a project. I found that Identity does not provide a mechanism for physically updating a userβs claim. With this method, MS gives the impression that you must delete the application from the user, so that when he gets access to the attributes of user authorization, he sees that the user does not have the application, and therefore it will not pass.
I had to create a separate Base Claims utility with views and a Controller to manage my user statements. For example, when I create a new user, I assign him various requirements. I also have an extended or custom Identity Manager class that I interact with to manage user requests, passwords, account lockout, adding new roles, and removing roles.
For presentation, I created custom HTML.Helper extension methods to help verify what the user has access to or not.
Some code examples are given below.
Identity Manager Class
public class IdentityManager { private RoleManager<IdentityRole> _roleManager; private UserManager<ApplicationUser> _userManager; private ApplicationDbContext _dbContext; private ApplicationSignInManager _signInManager; private DpapiDataProtectionProvider protectionProvider; public IdentityManager() { _dbContext = new ApplicationDbContext(); _roleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(_dbContext)); _userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(_dbContext)); protectionProvider = new DpapiDataProtectionProvider("Demo"); _userManager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>(protectionProvider.Create("ResetTokens")); } public IdentityManager(ApplicationSignInManager signmanager) { _dbContext = new ApplicationDbContext(); _signInManager = signmanager; _roleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(_dbContext)); _userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(_dbContext)); protectionProvider = new DpapiDataProtectionProvider("Demo"); _userManager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>(protectionProvider.Create("ResetTokens")); } public ApplicationSignInManager SignInManager { get { return _signInManager; } private set { _signInManager = value; } } public bool CreateNewUserRole(string role) { if (!RoleExist(role)) { var result = _roleManager.Create(new IdentityRole(role)); return result.Succeeded; } return false; } public bool DeleteUserRole(string role) { if (!RoleExist(role)) return true; var result = _roleManager.Delete(new IdentityRole(role)); return result.Succeeded; } public IdentityResult DeleteMemberShipUser(ApplicationUser user) { return _userManager.Delete(user); } public bool DeleteAllUtilityUsers(int utilityid) { try { var users = _dbContext.Users.Where(u => u.UtilityId == utilityid).ToList(); foreach (var user in users) { DeleteMemberShipUser(user); } } catch (Exception) { return false; } return true; } public bool RoleExist(string role) { return _roleManager.RoleExists(role); } public IdentityResult ChangePassword(ApplicationUser user, string token, string newpassword) { _userManager.UserValidator = new UserValidator<ApplicationUser>(_userManager) { AllowOnlyAlphanumericUserNames = false, RequireUniqueEmail = true }; return _userManager.ResetPassword(user.Id, token, newpassword); } public ApplicationUser GetUserByIdentityUserId(string userId) { return _userManager.FindById(userId); } public IdentityResult CreateNewUser(ApplicationUser user, string password) { _userManager.UserValidator = new UserValidator<ApplicationUser>(_userManager) { AllowOnlyAlphanumericUserNames = false, RequireUniqueEmail = true }; _userManager.PasswordValidator = new PasswordValidator { RequiredLength = 6, RequireNonLetterOrDigit = false, RequireDigit = false, RequireLowercase = false, RequireUppercase = false, };
User statements Authorize Attribute
public class ClaimsAuthorizeAttribute : AuthorizeAttribute { private readonly string _claimType; public ClaimsAuthorizeAttribute(string type) { _claimType = type; } public override void OnAuthorization(AuthorizationContext filterContext) { var user = (ClaimsPrincipal)HttpContext.Current.User; if (user.HasClaim(_claimType, "True")) { base.OnAuthorization(filterContext); } else { HandleUnauthorizedRequest(filterContext, _claimType + " Not Allowed "); } } protected void HandleUnauthorizedRequest(AuthorizationContext filterContext, string message) { filterContext.Result = new RedirectToRouteResult( new RouteValueDictionary { { "action", "ClaimNotAuthorized" }, { "controller", "Home" }, {"errorMessage", message } }); } public static bool AuthorizedFor(string claimType) { var user = (ClaimsPrincipal)HttpContext.Current.User; return user.HasClaim(claimType, "True"); } }
Application for use
[ClaimsAuthorize(ClaimsData.EditCustomer)] public ActionResult Index(string customerNo = "", int filterID = 0, int filterStatusID = 0)
View razor usage
public static bool AuthorizedFor(this HtmlHelper htmlHelper, string claimType) { if (!string.IsNullOrEmpty(claimType)) { var user = (ClaimsPrincipal)System.Web.HttpContext.Current.User; return user.HasClaim(claimType, "True"); } return false; }
HTML string rendering if claims passed
public static MvcHtmlString RenderToastrHiddenInputs(this HtmlHelper htmlHelper, object success, object info, object warning, object error, string claimType) { if (AuthorizedFor(htmlHelper, claimType)) { var html = string.Format(@" <input type='hidden' id='success' value='{0}' /> <input type='hidden' id='info' value='{1}' /> <input type='hidden' id='warning' value='{2}' /> <input type='hidden' id='error' value='{3}' />", success, info, warning, error); return new MvcHtmlString(html); } return null; }
Hope all this makes sense :)