Как аннулировать претензии с помощью идентификатора ASP.NET?

Я просто обновил некоторые из моих приложений до ASP.NET MVC 5. Я использовал членство в ASP.NET целую вечность и изучал возможность перехода на идентификатор ASP.NET.

Я создаю небольшое тестовое приложение, и у меня есть работа с аутентификацией (против активного каталога и специальной схемы SQL Server в зависимости от пользователя) и даже авторизации, добавив заявки на роль в ClaimsIdentity, прежде чем подписывать пользователя в (по-видимому, атрибут Authorize не соответствует действительности).

Охладно, что претензии сохраняются в cookie аутентификации по умолчанию. Однако это создает проблему, когда информация о пользователе изменилась (т.е. Они добавлены или удалены из роли).

Очевидно, что я могу свернуть свой собственный атрибут Authorize, как я всегда делал раньше. Если я это сделаю, я просто пропустил бы все заявки и просто проверил бы роли в базе данных для каждого запроса.

Есть ли способ использовать претензии в Identity ASP.NET и знать, когда они больше недействительны? Предоставляет ли инфраструктура любые варианты решения этой проблемы?

Ответ 2

Недавно я реализовал набор функций на основе утверждений в проекте. Я обнаружил, что Identity не предоставляет механизм для физического обновления утверждения пользователя. При таком способе MS создается впечатление, что вы должны удалить заявку от пользователя, чтобы при получении доступа к атрибутам пользовательской авторизации он увидел, что у пользователя нет заявки, и, следовательно, он не пройдет.

Я должен был создать отдельную утилиту Base Claims с представлениями и Controller для управления моими пользовательскими утверждениями. Например, когда я создаю нового пользователя, я назначаю ему различные требования. У меня также есть расширенный или пользовательский класс Identity Manager, с которым я взаимодействую, чтобы управлять заявками пользователей, паролями, блокировкой учетной записи, добавлением новых ролей и удалением ролей.

Для представления я создал пользовательские методы расширения HTML.Helper, чтобы помочь проверить, к чему у пользователя есть доступ или нет.

Некоторые примеры кода приведены ниже.

Класс Identity Manager

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,
            };

            // Configure user lockout defaults
            _userManager.UserLockoutEnabledByDefault = false;
            _userManager.DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5);
            _userManager.MaxFailedAccessAttemptsBeforeLockout = 5;

            var result = _userManager.Create(user, password);
            return result;
        }

        public IdentityResult UpdateUser(ApplicationUser user)
        {
            return _userManager.Update(user);
        }

        public bool AddUserToRole(string userId, string roleName)
        {
            var result = _userManager.AddToRole(userId, roleName);
            return result.Succeeded;
        }

        public bool RemoveUserFromRole(string userId, string role)
        {
            var result = _userManager.RemoveFromRole(userId, role);
            return result.Succeeded;
        }

        public IList<string> GetUserRoles(string userid)
        {
            return _userManager.GetRoles(userid);
        }

        public string GetUserRole(string userid)
        {
            return _userManager.GetRoles(userid).FirstOrDefault();
        }

        public IdentityRole GetRoleByRoleName(string roleName)
        {
            return _roleManager.Roles.First(i => i.Name == roleName);
        }

        public string GetUserRoleId(string userId)
        {
            var userRole = GetUserRole(userId);
            if (string.IsNullOrWhiteSpace(userRole)) return null;

            var role = GetRoleByRoleName(userRole);
            return role.Id;
        }

        public IdentityResult CreateNewSystemRole(IdentityRole role)
        {
            return !RoleExist(role.Name) ? _roleManager.Create(role) : new IdentityResult(new List<string> { "Role Already Exists" });
        }

        public List<IdentityRole> GetAllRoles()
        {
            return _roleManager.Roles.ToList();
        }

        public bool IsUserInRole(string role, string userName)
        {
            var user = _userManager.FindByName(userName);
            return _userManager.IsInRole(user.Id, role);
        }

        public ApplicationUser GetUserByUserName(string username)
        {
            return _userManager.FindByName(username);
        }

        public string GenerateResetToken(string userid)
        {
            return _userManager.GeneratePasswordResetToken(userid);
        }

        public IdentityResult SetLockStatus(string userid, bool lockstatus)
        {
            return _userManager.SetLockoutEnabled(userid, lockstatus);
        }

        public IdentityResult AddUserClaim(string userId, Claim claim)
        {
            return _userManager.AddClaim(userId, claim);
        }

        public void AddRoleClaim(string roleId, string claimType, string claimValue, int utilityid, string description)
        {
            try
            {
                _userManager.UserValidator = new UserValidator<ApplicationUser>(_userManager)
                {
                    AllowOnlyAlphanumericUserNames = false,
                    RequireUniqueEmail = true
                };

                var roleClaim = new AspNetRoleClaims()
                {
                    RoleId = roleId,
                    ClaimType = claimType,
                    ClaimValue = claimValue,
                    UtilityId = utilityid,
                    Description = description
                };

                _dbContext.AspNetRoleClaims.Add(roleClaim);
                _dbContext.SaveChanges();
            }
            catch (Exception ex)
            {
                throw new IdentityNotMappedException(ex.Message, ex);
            }
        }

        public IList<Claim> GetUserClaims(string userId)
        {
            return _userManager.GetClaims(userId);
        }

        public IdentityResult RemoveUserClaim(string userId, string claimType)
        {
            _userManager.UserValidator = new UserValidator<ApplicationUser>(_userManager)
            {
                AllowOnlyAlphanumericUserNames = false,
                RequireUniqueEmail = true
            };

            var claim = _userManager.GetClaims(userId).FirstOrDefault(t => t.Type == claimType);
            if (claim == null) return IdentityResult.Success;

            return _userManager.RemoveClaim(userId, claim);
        }

        public void DeleteRole(string id)
        {
            var language = new LanguageCodeLookup();
            var aspNetRoles = _dbContext.Roles.FirstOrDefault(r => r.Id == id);

            if (aspNetRoles == null)
                throw new Exception(language.RoleDoesNotExist);
            if (aspNetRoles.Name == "Utility Administrator" ||
                aspNetRoles.Name == "Content Manager" ||
                aspNetRoles.Name == "System Administrator" ||
                aspNetRoles.Name == "Customer Accounts Manager")
                throw new Exception(language.CannotDeleteDefaultRoles);
            if (aspNetRoles.Users.Count > 0)
                throw new Exception(language.CannotDeleteRolesWithUsers);
            _dbContext.Roles.Remove(aspNetRoles);
            _dbContext.SaveChanges();
        }

        public IdentityRole GetRole(string id)
        {
            return _dbContext.Roles.FirstOrDefault(r => r.Id == id);
        }
    }

Пользовательские утверждения Авторизовать Атрибут

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");
        }
    }

Заявка на использование

[ClaimsAuthorize(ClaimsData.EditCustomer)]
public ActionResult Index(string customerNo = "", int filterID = 0, int filterStatusID = 0)

Просмотр использования бритвы

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, если претензии пройдены

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;
    }

Надеюсь, все это имеет смысл :)