Eleitor e mecanismo de votação da gestão de autoridade do Spring Security

Autor: Jiangnan pouca chuva

Fonte: https://mp.weixin.qq.com/s/sU97RQjQq2-XXQt49LkSeQ

Hoje vamos falar sobre o mecanismo de votação e dispositivo de votação no Spring Security.

Quando um usuário deseja acessar um recurso protegido no Spring Security, o usuário tem algumas funções, e o acesso ao recurso também requer algumas funções. Ao comparar as funções que o usuário possui e as funções exigidas pelo recurso, o dispositivo de votação e a votação são usados mecanismo.

Quando um usuário deseja acessar um determinado recurso, o eleitor vota a favor ou contra de acordo com a função do usuário, e o método de votação é baseado no resultado do eleitor.

No Spring Security, três mecanismos de votação são fornecidos por padrão.Claro, também podemos definir completamente nós mesmos em vez do mecanismo de votação e dispositivo de votação fornecido pelo sistema.Isso também é possível.

Neste artigo, Song Ge se concentrará na introdução de três mecanismos de votação e o dispositivo de votação padrão.

1. Dispositivo de votação

Vejamos primeiro a máquina de votação.

No Spring Security, o eleitor é regulado pela interface AccessDecisionVoter. Vejamos a implementação da interface AccessDecisionVoter:

Eleitor e mecanismo de votação da gestão de autoridade do Spring Security

 

Como você pode ver, existem muitas implementações de dispositivos de votação. Podemos escolher um ou mais deles, ou personalizar dispositivos de votação. O dispositivo de votação padrão é WebExpressionVoter.

Vejamos a definição de AccessDecisionVoter:

public interface AccessDecisionVoter<S> {
 int ACCESS_GRANTED = 1;
 int ACCESS_ABSTAIN = 0;
 int ACCESS_DENIED = -1;
 boolean supports(ConfigAttribute attribute);
 boolean supports(Class<?> clazz);
 int vote(Authentication authentication, S object,
   Collection<ConfigAttribute> attributes);
}

Deixe-me explicar um pouco:

  1. Em primeiro lugar, três constantes são definidas. O significado de cada constante pode ser visto a partir do nome da constante. 1 significa aprovação; 0 significa abstenção; -1 significa rejeição.
  2. Dois métodos de suporte são usados ​​para determinar se o eleitor apoia o pedido atual.
  3. Votar é o método de votação específico. Implementado em diferentes classes de implementação. Três parâmetros, autenticação representa o assunto do login atual; o objeto é um ilterInvocation, que encapsula a solicitação atual; atributos representam o conjunto de funções exigidas pela interface acessada no momento.

Vejamos a implementação de vários dispositivos de votação, respectivamente.

1.1 RoleVoter

RoleVoter é usado principalmente para determinar se a solicitação atual tem a função exigida pela interface, vamos dar uma olhada em seu método de votação:

public int vote(Authentication authentication, Object object,
  Collection<ConfigAttribute> attributes) {
 if (authentication == null) {
  return ACCESS_DENIED;
 } int result = ACCESS_ABSTAIN;
 Collection<? extends GrantedAuthority> authorities = extractAuthorities(authentication); for (ConfigAttribute attribute : attributes) {
  if (this.supports(attribute)) {
   result = ACCESS_DENIED;   for (GrantedAuthority authority : authorities) {
    if (attribute.getAttribute().equals(authority.getAuthority())) {
     return ACCESS_GRANTED;
    }   }  } } return result;
}

A lógica de julgamento deste método é muito simples. Se o assunto do login atual for nulo, ele retornará diretamente ACCESS_DENIED para indicar que o acesso foi negado; caso contrário, extraia as informações da função da autenticação do assunto do login atual e compare-as com os atributos. Se tiver a função necessária nos atributos Qualquer um, ACCESS_GRANTED é retornado para indicar que o acesso é permitido. Por exemplo, a função nos atributos é [a, b, c] e, se o usuário atual tiver a, o acesso é permitido e não há necessidade de ter todas as três funções ao mesmo tempo.

Há outro lugar para prestar atenção, que é o método de suporte do RoleVoter, vamos dar uma olhada:

public class RoleVoter implements AccessDecisionVoter<Object> {
 private String rolePrefix = "ROLE_";
 public String getRolePrefix() {
  return rolePrefix;
 } 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;
  } } public boolean supports(Class<?> clazz) {
  return true;
 }}

Como você pode ver, um prefixo rolePrefix está envolvido aqui. Este prefixo é ROLE_. No método de suporte, apenas se o prefixo de função do sujeito for ROLE_, o método de supoorts retornará verdadeiro e o votador terá efeito.

1.2 RoleHierarchyVoter

RoleHierarchyVoter é uma subclasse de RoleVoter. Com base no julgamento de função de RoleVoter, o gerenciamento hierárquico de função é introduzido, ou seja, herança de função. Para herança de função, os amigos podem consultar o artigo anterior de Song Ge (Como permitir que superiores tenham propriedade no Spring Security Todas as permissões subordinadas?).

O método de votação da classe RoleHierarchyVoter é o mesmo que o RoleVoter. A única diferença é que a classe RoleHierarchyVoter substitui o método extractAuthorities.

@Override
Collection<? extends GrantedAuthority> extractAuthorities(
  Authentication authentication) { return roleHierarchy.getReachableGrantedAuthorities(authentication
   .getAuthorities());
}

Após as funções serem colocadas em camadas, você precisa obter as funções reais que possui por meio do método getReachableGrantedAuthorities. Para obter detalhes, consulte: Como permitir que o superior tenha todas as permissões do subordinado no Spring Security? Um artigo.

1.3 WebExpressionVoter

Este é um dispositivo de votação baseado no controle de permissão de expressão. Song Ge passará algum tempo conversando com amigos sobre o controle de permissão baseado em expressões. Aqui não faremos muito para expandir, basta olhar seu método de votação:

public int vote(Authentication authentication, FilterInvocation fi,
  Collection<ConfigAttribute> attributes) {
 assert authentication != null;
 assert fi != null;
 assert attributes != null;
 WebExpressionConfigAttribute weca = findConfigAttribute(attributes); if (weca == null) {
  return ACCESS_ABSTAIN;
 } EvaluationContext ctx = expressionHandler.createEvaluationContext(authentication,   fi); ctx = weca.postProcess(ctx, fi); return ExpressionUtils.evaluateAsBoolean(weca.getAuthorizeExpression(), ctx) ? ACCESS_GRANTED
   : ACCESS_DENIED;}

Se você é proficiente no uso de SpEL, este código deve ser considerado fácil de entender, mas de acordo com minha experiência, embora haja algumas cenas de SpEL usadas no trabalho real, mas não muitas, então pode haver muitos pequenos parceiros que não entendem o uso de SpEL , Isso precisa ser revisado pelos amigos, também recomendo um bom artigo para todos: https://www.cnblogs.com/larryzeal/p/5964621.html.

O código aqui é, na verdade, construir um objeto weca com base nos atributos de entrada, construir um objeto ctx com base nos parâmetros de autenticação passados ​​e, finalmente, chamar o método evaluateAsBoolean para determinar se as permissões correspondem.

Os três dispositivos de votação apresentados acima são os três que mais usamos no desenvolvimento real.

1.4 Outro

Além disso, existem alguns dispositivos de votação mais populares, Song Ge também falou um pouco, os amigos entendem.

Jsr250Voter

Eleitores que lidam com anotações de permissão Jsr-250, como @PermitAll, @DenyAll etc.

AuthenticatedVoter

AuthenticatedVoter é usado para determinar se existem três funções IS_AUTHENTICATED_FULLY, IS_AUTHENTICATED_REMEMBERED, IS_AUTHENTICATED_ANONYMOUSLY em ConfigAttribute.

IS_AUTHENTICATED_FULLY significa que o usuário autenticado no momento deve ser autenticado por nome de usuário / senha e a autenticação por RememberMe é inválida.

IS_AUTHENTICATED_REMEMBERED significa que o usuário conectado no momento deve ser autenticado por meio do RememberMe.

IS_AUTHENTICATED_ANONYMOUSLY indica que o usuário conectado no momento deve ser um usuário anônimo.

Quando o projeto apresenta o RememberMe e deseja distinguir entre diferentes métodos de autenticação, você pode considerar este eleitor.

AbstractAclVoter

Fornece um método auxiliar para escrever opções de ACL do objeto de domínio, que não está vinculado a nenhum sistema ACL específico.

PreInvocationAuthorizationAdviceVoter

As permissões processadas usando as anotações @PreFilter e @PreAuthorize são autorizadas por PreInvocationAuthorizationAdvice.

Obviamente, se esses dispositivos de votação não atenderem às necessidades, eles também podem ser personalizados.

2. Mecanismo de votação

Um pedido não tem necessariamente apenas um eleitor, também pode haver vários eleitores, portanto, precisamos de um mecanismo de votação com base no eleitor.

Eleitor e mecanismo de votação da gestão de autoridade do Spring Security

 

Existem três classes principais relacionadas à votação:

  • AffirmativeBased
  • ConsensusBased
  • UnanimousBased

Sua relação de herança é mostrada acima.

Os três tomadores de decisão chamarão todos os dispositivos de votação no projeto, e o tomador de decisão padrão é AffirmativeBased.

As diferenças entre os três tomadores de decisão são as seguintes:

  • AffirmativeBased: Se um eleitor concordar, ele é aprovado.
  • ConsensusBased: O eleitor majoritário concorda em ser aprovado, caso haja empate, depende do valor do parâmetro allowIfEqualGrantedDeniedDecisions.
  • UnanimousBased Todos os eleitores concordam, o pedido é aprovado.

A lógica de julgamento específico aqui é relativamente simples, Song Ge não postará o código-fonte e amigos interessados ​​podem ver por si mesmos.

3. Onde configurar

Quando usamos controle de permissão baseado em expressão, como o seguinte:

http.authorizeRequests()
        .antMatchers("/admin/**").hasRole("admin")
        .antMatchers("/user/**").hasRole("user")
        .anyRequest().fullyAuthenticated()

Em seguida, o eleitor e o decisor padrão são configurados no método AbstractInterceptUrlConfigurer # createDefaultAccessDecisionManager:

private AccessDecisionManager createDefaultAccessDecisionManager(H http) {
 AffirmativeBased result = new AffirmativeBased(getDecisionVoters(http));
 return postProcess(result);
}List<AccessDecisionVoter<?>> getDecisionVoters(H http) {
 List<AccessDecisionVoter<?>> decisionVoters = new ArrayList<>();
 WebExpressionVoter expressionVoter = new WebExpressionVoter();
 expressionVoter.setExpressionHandler(getExpressionHandler(http)); decisionVoters.add(expressionVoter); return decisionVoters;
}

Aqui você pode ver o tomador de decisão padrão e o dispositivo de votação, e depois que o objeto de tomador de decisão AffirmativeBased é criado, ele também chama o método postProcess para registrá-lo no contêiner Spring. Combinado com os artigos anteriores desta série, você sabe, se quisermos Modificar o objeto é muito fácil:

http.authorizeRequests()
        .antMatchers("/admin/**").hasRole("admin")
        .antMatchers("/user/**").hasRole("user")
        .anyRequest().fullyAuthenticated()        .withObjectPostProcessor(new ObjectPostProcessor<AffirmativeBased>() {
            @Override            public <O extends AffirmativeBased> O postProcess(O object) {
                List<AccessDecisionVoter<?>> decisionVoters = new ArrayList<>();
                decisionVoters.add(new RoleHierarchyVoter(roleHierarchy()));
                AffirmativeBased affirmativeBased = new AffirmativeBased(decisionVoters);
                return (O) affirmativeBased;
            }        })        .and()        .csrf()        .disable();

Isso é apenas para dar uma demonstração. Normalmente, não precisamos modificar dessa forma. Quando usamos métodos de configuração de permissão diferentes, serão configurados automaticamente dispositivos de votação e tomadores de decisão correspondentes. Ou configuramos manualmente o eleitor e o decisor.Se o sistema estiver configurado, não precisamos modificá-lo na maioria dos casos.

4. Resumo

Este artigo compartilha principalmente com amigos os votantes e tomadores de decisão no Spring Security

Acho que você gosta

Origin blog.csdn.net/weixin_45132238/article/details/108537179
Recomendado
Clasificación