Spring Security Tutorial Vol 8. Введение в компонент AccessDecisionVoter

Spring

Восьмой выпуск введения компонента AccessDecisionVoter

В этом выпуске мы в основном представим компоненты контроля доступа, три мушкетера, отвечающие за роль правил авторизации -AccessDecisionVoterинтерфейс. И несколько баз, предоставляемых Spring Security по умолчанию.AccessDecisionVoterКласс реализации делает подробное описание, и, наконец, мы настроимAccessDecisionVoterРеализация используется для практической иллюстрации.

  • AccessDecisionVoterОписание интерфейса
  • Весенняя безопасностьAccessDecisionVoterOни
  • Пример настройки: по времениAccessDecisionVoter

1. Описание интерфейса AccessDecisionVoter

AccessDecisionVoter接口说明
AccessDecisionVoterОсновная ответственность заключается в оценке соответствующих правил доступа и возможности авторизации текущих правил доступа.AccessDecisionVoterОсновной метод интерфейса фактически такой же, как и предыдущий.AuthenticationProviderочень похожий.

	boolean supports(ConfigAttribute attribute);

	int vote(Authentication authentication, S object,
			Collection<ConfigAttribute> attributes);
  • Метод supports используется для определения того, является ли текущийConfigAttributeПоддерживаются ли правила доступа;
  • Если он поддерживается, метод голосования оценит и проголосует за него и вернет соответствующий результат авторизации. Есть три окончательных результата авторизации, а именно согласие, воздержание и возражение. Честно говоря, это правило по своему характеру похоже на голосование в Совете Безопасности ООН. Если для текущего посещения может быть несколько правил, каждоеAccessDecisionVoterОтдайте свой собственный голос, окончательный результат голосования зависит от текущих правил голосования, например, больше 1/3 или больше половины. И решение правил голосования помещается вAccessDecisionManagerзавершить.
	int ACCESS_GRANTED = 1;
	int ACCESS_ABSTAIN = 0;
	int ACCESS_DENIED = -1;

Во-вторых, весенняя безопасностьAccessDecisionVoterOни

через вышеуказанное дляAccessDecisionVoterОсновное введение, мы узнали большой принцип дизайна:AccessDecisionVoterреализуется для удовлетворения соответствующих правилConfigAttribute. в целомAccessDecisionVoterС участиемConfigAttributeсоответствующий. Вернемся к основным из них, которые мы представили в прошлом выпуске.ConfigAttributeвыполнить:

  • WebExpressionConfigAttribute на основе веб-выражений
  • SecurityConfig на основе аннотации @Secured
  • PostInvocationExpressionAttribute на основе аннотации @Pre-@Post Мы можем легко найти соответствующую дверь его двери на картинке ниже.AccessDecisionVoter.
    主要的AccessDecisionVoter
    Здесь мы сосредоточимся на конфигурации SecurityConfig, используемой в индивидуальном сценарии, и на двух ее значениях по умолчанию.AccessDecisionVoter:
  • RoleVoter
  • AuthenticatedVoter Во-первых, давайте вспомним форму использования SecurityConfig, которая заключается в написании выражения с использованием аннотации @Secured:
@Secured("ROLE_USER")
@Secured("IS_AUTHENTICATED_ANONYMOUSLY")

мы изучилиAccessDecisionVoterа такжеConfigAttributeОб ассоциативных отношениях судят по методу опор, мы соответственноRoleVoterа такжеAuthenticatedVoterПросмотрите метод поддержки:

RoleVoter RoleVoterЭто основной компонент ролевых правил по умолчанию в Spring Security. Чтобы создать пользователя в UserDetailsService, нам всем нужно установить информацию о роли для пользователя. В конфигурации по умолчанию информация о роли пользователя хранится в виде «ROLE_» + имя роли. соответствующийRoleVoterВ методе supports будет оцениваться, начинается ли выражение с «ROLE_» в качестве соответствующего включенного правила. Если регулярное выражение начинается с ROLE_,RoleVoterОн будет проходить, чтобы увидеть, есть ли соответствующая роль в аутентификации, если она существует, она вернет проход, а если она не существует, она вернет отказ.

public class RoleVoter implements AccessDecisionVoter<Object> {
	// ~ Instance fields
	// ================================================================================================

	private String rolePrefix = "ROLE_";

	// ~ Methods
	// ========================================================================================================

	public String getRolePrefix() {
		return rolePrefix;
	}

	/**
	 * Allows the default role prefix of <code>ROLE_</code> to be overridden. May be set
	 * to an empty value, although this is usually not desirable.
	 *
	 * @param rolePrefix the new prefix
	 */
	public void setRolePrefix(String rolePrefix) {
		this.rolePrefix = rolePrefix;
	}

	public boolean supports(ConfigAttribute attribute) {
		if ((attribute.getAttribute() != null)
				&& attribute.getAttribute().startsWith(getRolePrefix())) {
			return true;
		}
		else {
			return false;
		}
	}
}

AuthenticatedVoter AuthenticatedVoterСценарий использования весьма специфичен: это не контроль доступа на основе идентификационной информации, аAuhenticationРешение формы аутентификации. В предыдущей части аутентификации мы узнали, что в дизайне Spring Security мы можем использовать метод RememberMeService для авторизации входа без использования имени пользователя и пароля, а с помощью информации, хранящейся в файле cookie. В ежедневной инженерии для некоторых чувствительных операций мы требуем, чтобы текущий пользователь не был пользователем, который выполняет авторизацию и аутентификацию на основе истории.Логин расширяет действие сеанса, а не логин на основе куки месяц назад у пользователя. В этом сценарии мы можем использовать@Secured("IS_AUTHENTICATED_FULLY")Чтобы ограничить пользователя полностью аутентифицированным пользователем, а не пользователем, аутентифицированным RememberMe. существуетAuthenticatedVoterВ методе supports он будет судить, что текущее выражение является контролем доступа для трех поддерживаемых им методов аутентификации:

  • IS_AUTHENTICATED_FULLY
  • IS_AUTHENTICATED_REMEMBERED
  • IS_AUTHENTICATED_ANONYMOUSLY Если есть точное совпадение, текущийAuthenticationОценивается режим авторизации объекта и возвращается соответствующий результат голосования.
public class AuthenticatedVoter implements AccessDecisionVoter<Object> {
	// ~ Static fields/initializers
	// =====================================================================================

	public static final String IS_AUTHENTICATED_FULLY = "IS_AUTHENTICATED_FULLY";
	public static final String IS_AUTHENTICATED_REMEMBERED = "IS_AUTHENTICATED_REMEMBERED";
	public static final String IS_AUTHENTICATED_ANONYMOUSLY = "IS_AUTHENTICATED_ANONYMOUSLY";
	// ~ Instance fields
	// ================================================================================================

	private AuthenticationTrustResolver authenticationTrustResolver = new AuthenticationTrustResolverImpl();

	// ~ Methods
	// ========================================================================================================

	private boolean isFullyAuthenticated(Authentication authentication) {
		return (!authenticationTrustResolver.isAnonymous(authentication) && !authenticationTrustResolver
				.isRememberMe(authentication));
	}

	public boolean supports(ConfigAttribute attribute) {
		if ((attribute.getAttribute() != null)
				&& (IS_AUTHENTICATED_FULLY.equals(attribute.getAttribute())
						|| IS_AUTHENTICATED_REMEMBERED.equals(attribute.getAttribute()) || IS_AUTHENTICATED_ANONYMOUSLY
							.equals(attribute.getAttribute()))) {
			return true;
		}
		else {
			return false;
		}
	}
}

3. Индивидуальный пример: AccessDecisionVoter на основе времени

заAccessDecisionVoterПосле базового понимания структуры, обязанностей и классов реализации, представленных в Spring Security. Мы подкрепляем это понимание индивидуальным примером. Мы настроим управление доступом на основе времени, доступ к которому возможен только тогда, когда количество минут в системном времени нечетное, например, 10:01 можно получить доступ, но 10:02 нельзя.

правила дизайна

Во-первых, мы разрабатываем правила доступа. мы похожиRoleVoterа такжеAuthenticatedVoterОн также расширяется на основе выражений, аннотированных @Secured. Сформулированное нами правило называется "MINUTE_ODD". Когда уровень метода аннотирован @Secured("MINUTE_ODD"), это означает, что текущий метод может быть доступен только тогда, когда количество минут, удовлетворяющих системному времени, нечетно.

Настроить MinuteBasedVoter

Далее пишемMinuteBasedVoterрасширятьAuthenticatedVoter.

public class MinuteBasedVoter implements AccessDecisionVoter {
}

Затем мы реализуем соответствующий метод поддержки, чтобы завершить наше суждение о наших предложенных правилах. Когда атрибут выражения входного параметра ConfigAttribute согласуется с нашей предустановкой «MINUTE_ODD», мы возвращаем значение true, чтобы сообщить платформе,MinuteBasedVoterДля этого правила требуется операция голосования.

public class MinuteBasedVoter implements AccessDecisionVoter {
    public static final String IS_MINUTE_ODD= "MINUTE_ODD";

    @Override
    public boolean supports(ConfigAttribute attribute) {
        if ((attribute.getAttribute() != null)
                && attribute.getAttribute().equals(IS_MINUTE_ODD)) {
            return true;
        }
        else {
            return false;
        }
    }


    @Override
    public boolean supports(Class clazz) {
        return true;
    }
}

Наконец, мы завершаем основную бизнес-логику голосования: когда время нечетное, мы голосуем за него, а когда время четное, мы голосуем за чистое голосование.Без голосования.

    @Override
    public int vote(Authentication authentication, Object object, Collection collection) {
        if(LocalDateTime.now().getMinute() % 2 != 0){
            return ACCESS_GRANTED;

        }else{
            return ACCESS_DENIED;
        }
    }

Конфигурация Java

Наконец, поговорим о том, как новыйAccessDecisionVoterдобавить к существующимAccessDecisionManagerсередина. Я также погуглил китайский мир и английский мир.Про этот удобный пример есть официальные документы, и там действительно всякое. Наиболее распространенным является реорганизация AccessDecisionManager и внедрение его обратно в Spring Security.Я не рекомендую создавать новый AccessDecisionManager в методе. Поскольку процесс инициализации AccessDecisionManager включает более чемAccessDecisionVoter, Случайно некоторые из поведений по умолчанию могут быть настроены неправильно из-за отсутствия набора компонентов. Метод, который я рекомендую новичкам, состоит в том, чтобы создать новый класс Java Config для аннотаций на уровне методов, таких как расширение Secured, а затем переписать инициализацию в исходной среде.AccessDecisionManagerМетоды:

@EnableGlobalMethodSecurity(prePostEnabled = true,securedEnabled = true)
@Configuration
public class MethodSecurityConfiguration extends GlobalMethodSecurityConfiguration {
    @Override
    protected AccessDecisionManager accessDecisionManager() {
        AffirmativeBased affirmativeBased = (AffirmativeBased) super.accessDecisionManager();
        affirmativeBased.getDecisionVoters().add(new MinuteBasedVoter());
        return affirmativeBased;
    }
}

Хотя код может быть уродливым, и есть сильные типы конверсий, его относительно легко понять и многое контролировать. После добавления конфигурации Java для MethodSecurityConfiguration мы увидим следующий журнал голосования, когда метод контроллера ограничен аннотацией @Secured("MINUTE_ODD"):

Secure object: ReflectiveMethodInvocation: public java.lang.String Attributes: [MINUTE_ODD]
Voter: org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter@456f4439, returned: 0
Voter: org.springframework.security.access.vote.RoleVoter@38b13fa8, returned: 0
Voter: org.springframework.security.access.vote.AuthenticatedVoter@590fa701, returned: 0
Voter: com.newnil.demo.security.MinuteBasedVoter@135c04e9, returned: 1
Authorization successful

AccessDecisionVoterКомпоненты голосуют по очереди, и поскольку текущее время нечетное, наш MinuteBasedVoter отдает положительный голос со значением 1.

конец

Подробности этой проблемыAccessDecisionVoterЭтот компонент обеспечивает основное суждение и голосование для управления доступом. В то же время мы также узнали, как это работает, благодаря предоставлению по умолчанию и индивидуальной реализации фреймворка. В следующем выпуске мы поставим последний основной компонентAccessDecisionManagerкак всеAccessDecisionVoterПодведите итоги голосования и объясните, как правила оценки влияют на окончательный результат авторизации. Увидимся в следующий раз.