Maison  >  Article  >  Java  >  Exemple de gestion du contrôle des autorisations Spring Security personnalisé en Java (Pratique)

Exemple de gestion du contrôle des autorisations Spring Security personnalisé en Java (Pratique)

黄舟
黄舟original
2017-03-06 10:16:302247parcourir

Cet article présente principalement l'exemple personnalisé de gestion du contrôle des autorisations Spring Security en Java (article pratique). Les amis intéressés peuvent s'y référer.

Description de l'arrière-plan

Un contrôle précis des autorisations est requis dans le projet, jusqu'à la méthode http de l'URL (qui satisfait au repos, par exemple : http://www. php.cn/ , certains rôles ne peuvent que visualiser (HTTP GET), mais n'ont pas le droit d'ajouter, de modifier ou de supprimer (POST, PUT, DELETE)).

Conception du tableau

Pour éviter tout soupçon, seuls les champs clés à utiliser sont répertoriés, veuillez déterminer le reste par vous-même.

1.admin_user table utilisateur administrateur, champs clés (id, role_id).

Table de rôles 2.t_role, champs clés (id, privilège_id).

3.t_privilege table d'autorisations, champs clés (id, url, méthode)

Inutile d'en dire plus sur la relation entre les trois tables, vous pouvez la voir d'un coup d'œil sur les champs dehors.

Analyse pré-implémentation

Nous pouvons penser à l'envers :

Pour comprendre nos besoins, l'étape la plus critique est de laisser AccessDecisionManager de Spring Security juger Si l'URL demandée httpmethod correspond à la configuration de notre base de données. Cependant, AccessDecisionManager ne détermine pas les électeurs associés ayant des besoins similaires. Par conséquent, nous devons personnaliser une implémentation d'électeur (la stratégie AffirmativeBased enregistrée par défaut est que tant qu'un électeur vote ACCESS_GRANTED, il sera déterminé comme adopté, ce qui est conforme. avec notre besoin). Après avoir implémenté le voteur, il y a un paramètre clé (Collection

Pour résumer les étapes de réflexion :

1. Personnalisez l'implémentation du voteur.

2. Personnalisez l'implémentation de ConfigAttribute.

3. Personnalisez l'implémentation de SecurityMetadataSource

4. L'authentification contient des instances d'utilisateur (il va sans dire, tout le monde aurait déjà dû le faire

5. Personnaliser l'implémentation de GrantedAuthority).

Combat réel du projet

1. Implémentation personnalisée de GrantedAuthority

UrlGrantedAuthority.java

public class UrlGrantedAuthority implements GrantedAuthority {

  private final String httpMethod;

  private final String url;

  public UrlGrantedAuthority(String httpMethod, String url) {
    this.httpMethod = httpMethod;
    this.url = url;
  }

  @Override
  public String getAuthority() {
    return url;
  }

  public String getHttpMethod() {
    return httpMethod;
  }

  public String getUrl() {
    return url;
  }

  @Override
  public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;

    UrlGrantedAuthority target = (UrlGrantedAuthority) o;
    if (httpMethod.equals(target.getHttpMethod()) && url.equals(target.getUrl())) return true;
    return false;
  }

  @Override
  public int hashCode() {
    int result = httpMethod != null ? httpMethod.hashCode() : 0;
    result = 31 * result + (url != null ? url.hashCode() : 0);
    return result;
  }
}

2. Instance utilisateur d'authentification personnalisée

public class SystemUser implements UserDetails {

  private final Admin admin;

  private List<MenuOutput> menuOutputList;

  private final List<GrantedAuthority> grantedAuthorities;

  public SystemUser(Admin admin, List<AdminPrivilege> grantedPrivileges, List<MenuOutput> menuOutputList) {
    this.admin = admin;
    this.grantedAuthorities = grantedPrivileges.stream().map(it -> {
      String method = it.getMethod() != null ? it.getMethod().getLabel() : null;
      return new UrlGrantedAuthority(method, it.getUrl());
    }).collect(Collectors.toList());
    this.menuOutputList = menuOutputList;
  }

  @Override
  public Collection<? extends GrantedAuthority> getAuthorities() {
    return this.grantedAuthorities;
  }

  @Override
  public String getPassword() {
    return admin.getPassword();
  }

  @Override
  public String getUsername() {
    return null;
  }

  @Override
  public boolean isAccountNonExpired() {
    return true;
  }

  @Override
  public boolean isAccountNonLocked() {
    return true;
  }

  @Override
  public boolean isCredentialsNonExpired() {
    return true;
  }

  @Override
  public boolean isEnabled() {
    return true;
  }

  public Long getId() {
    return admin.getId();
  }

  public Admin getAdmin() {
    return admin;
  }

  public List<MenuOutput> getMenuOutputList() {
    return menuOutputList;
  }

  public String getSalt() {
    return admin.getSalt();
  }
}

3. Implémentation d'UrlConfigAttribute personnalisée

public class UrlConfigAttribute implements ConfigAttribute {

  private final HttpServletRequest httpServletRequest;

  public UrlConfigAttribute(HttpServletRequest httpServletRequest) {
    this.httpServletRequest = httpServletRequest;
  }


  @Override
  public String getAttribute() {
    return null;
  }

  public HttpServletRequest getHttpServletRequest() {
    return httpServletRequest;
  }
}

4. Implémentation personnalisée de SecurityMetadataSource

public class UrlFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {

  @Override
  public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
    final HttpServletRequest request = ((FilterInvocation) object).getRequest();
    Set<ConfigAttribute> allAttributes = new HashSet<>();
    ConfigAttribute configAttribute = new UrlConfigAttribute(request);
    allAttributes.add(configAttribute);
    return allAttributes;
  }

  @Override
  public Collection<ConfigAttribute> getAllConfigAttributes() {
    return null;
  }

  @Override
  public boolean supports(Class<?> clazz) {
    return FilterInvocation.class.isAssignableFrom(clazz);
  }

}

5. Personnalisée mise en œuvre des électeurs

public class UrlMatchVoter implements AccessDecisionVoter<Object> {

 
  @Override
  public boolean supports(ConfigAttribute attribute) {
    if (attribute instanceof UrlConfigAttribute) return true;
    return false;
  }

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

  @Override
  public int vote(Authentication authentication, Object object, Collection<ConfigAttribute> attributes) {
    if(authentication == null) {
      return ACCESS_DENIED;
    }
    Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();

    for (ConfigAttribute attribute : attributes) {
      if (!(attribute instanceof UrlConfigAttribute)) continue;
      UrlConfigAttribute urlConfigAttribute = (UrlConfigAttribute) attribute;
      for (GrantedAuthority authority : authorities) {
        if (!(authority instanceof UrlGrantedAuthority)) continue;
        UrlGrantedAuthority urlGrantedAuthority = (UrlGrantedAuthority) authority;
        if (StringUtils.isBlank(urlGrantedAuthority.getAuthority())) continue;
        //如果数据库的method字段为null,则默认为所有方法都支持
        String httpMethod = StringUtils.isNotBlank(urlGrantedAuthority.getHttpMethod()) ? urlGrantedAuthority.getHttpMethod()
            : urlConfigAttribute.getHttpServletRequest().getMethod();
        //用Spring已经实现的AntPathRequestMatcher进行匹配,这样我们数据库中的url也就支持ant风格的配置了(例如:/xxx/user/**)    
        AntPathRequestMatcher antPathRequestMatcher = new AntPathRequestMatcher(urlGrantedAuthority.getAuthority(), httpMethod);
        if (antPathRequestMatcher.matches(urlConfigAttribute.getHttpServletRequest()))
          return ACCESS_GRANTED;
      }
    }
    return ACCESS_ABSTAIN;
  }
}

6. Implémentation personnalisée de FilterSecurityInterceptor

public class UrlFilterSecurityInterceptor extends FilterSecurityInterceptor {

  public UrlFilterSecurityInterceptor() {
    super();
  }

  @Override
  public void init(FilterConfig arg0) throws ServletException {
    super.init(arg0);
  }

  @Override
  public void destroy() {
    super.destroy();
  }

  @Override
  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    super.doFilter(request, response, chain);
  }

  @Override
  public FilterInvocationSecurityMetadataSource getSecurityMetadataSource() {
    return super.getSecurityMetadataSource();
  }

  @Override
  public SecurityMetadataSource obtainSecurityMetadataSource() {
    return super.obtainSecurityMetadataSource();
  }

  @Override
  public void setSecurityMetadataSource(FilterInvocationSecurityMetadataSource newSource) {
    super.setSecurityMetadataSource(newSource);
  }

  @Override
  public Class<?> getSecureObjectClass() {
    return super.getSecureObjectClass();
  }

  @Override
  public void invoke(FilterInvocation fi) throws IOException, ServletException {
    super.invoke(fi);
  }

  @Override
  public boolean isObserveOncePerRequest() {
    return super.isObserveOncePerRequest();
  }

  @Override
  public void setObserveOncePerRequest(boolean observeOncePerRequest) {
    super.setObserveOncePerRequest(observeOncePerRequest);
  }
}

Configuration des clés du fichier de configuration

<security:http>
  ...
  <security:custom-filter ref="filterSecurityInterceptor" before="FILTER_SECURITY_INTERCEPTOR" />
</security:http>

<security:authentication-manager alias="authenticationManager">
  <security:authentication-provider ref="daoAuthenticationProvider"/>
</security:authentication-manager>

<bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
  <constructor-arg>
    <list>
      <bean id="authenticatedVoter" class="org.springframework.security.access.vote.AuthenticatedVoter" />
      <bean id="roleVoter" class="org.springframework.security.access.vote.RoleVoter" />
      <bean id="urlMatchVoter" class="com.mobisist.app.security.access.voter.UrlMatchVoter" />
    </list>
  </constructor-arg>
</bean>

<bean id="securityMetadataSource" class="com.mobisist.app.security.access.UrlFilterInvocationSecurityMetadataSource" />

<bean id="filterSecurityInterceptor"
   class="com.mobisist.app.security.access.UrlFilterSecurityInterceptor">
  <property name="authenticationManager" ref="authenticationManager"/>
  <property name="accessDecisionManager" ref="accessDecisionManager"/>
  <property name="securityMetadataSource" ref="securityMetadataSource" />
</bean>

D'accord, profitez maintenant de votre contrôle des autorisations Spring Security Partons en voyage

Ce qui précède est le contenu de l'exemple personnalisé de gestion du contrôle des autorisations Spring Security en java (chapitre pratique). Pour plus de contenu connexe, veuillez faire attention au site Web PHP chinois (www.php.cn) 🎜>

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn