Spring Security 的 ACL 配置问题

Posted

技术标签:

【中文标题】Spring Security 的 ACL 配置问题【英文标题】:ACL configuration problems with Spring Security 【发布时间】:2015-11-19 11:32:56 【问题描述】:

我是 Spring 世界的新手,我正在使用 Spring Boot 1.2.5 和 Spring Security 3.1.2。由于我的项目要求,我需要配置 ACL 安全模型。我有以下 java 类配置:

@Configuration
public class ACLConfig 

    @Autowired
    DataSource dataSource;


    @Bean
    JdbcTemplate jdbcTemplate() 
        return new JdbcTemplate(dataSource);
    

    @Bean
    DataSourceTransactionManager transactionManager() 
        return new DataSourceTransactionManager(dataSource);
    

    @Bean
    EhCacheBasedAclCache aclCache() 
        EhCacheFactoryBean factoryBean = new EhCacheFactoryBean();
        EhCacheManagerFactoryBean cacheManager = new   EhCacheManagerFactoryBean();
        cacheManager.setAcceptExisting(true);
      cacheManager.setCacheManagerName(CacheManager.getInstance().getName());
        cacheManager.afterPropertiesSet();

        factoryBean.setName("aclCache");
        factoryBean.setCacheManager(cacheManager.getObject());
        factoryBean.setMaxBytesLocalHeap("16M");
        factoryBean.setMaxEntriesLocalHeap(0L);
        factoryBean.afterPropertiesSet();
        return new EhCacheBasedAclCache(factoryBean.getObject());
    

    @Bean
    LookupStrategy lookupStrategy() 
        return new BasicLookupStrategy(dataSource, aclCache(),  aclAuthorizationStrategy(), new ConsoleAuditLogger());
    

    @Bean
    AclAuthorizationStrategy aclAuthorizationStrategy() 
        return new AclAuthorizationStrategyImpl(new  SimpleGrantedAuthority("ROLE_SUPER_ADMIN"),
        new SimpleGrantedAuthority("ROLE_SUPER_ADMIN"),
        new SimpleGrantedAuthority("ROLE_SUPER_ADMIN"));
    

    @Bean
    JdbcMutableAclService aclService() 
        JdbcMutableAclService service = new     JdbcMutableAclService(dataSource, lookupStrategy(), aclCache());
        service.setClassIdentityQuery("select currval(pg_get_serial_sequence('acl_class', 'id'))");
        service.setSidIdentityQuery("select currval(pg_get_serial_sequence('acl_sid', 'id'))");
        return service;
    

    @Bean
    AclEntryVoter aclDeleteVoter()
    
        AclEntryVoter voter = new   AclEntryVoter(aclService(),"ACL_NOMCITY_DELETE", new Permission[]  BasePermission.DELETE);
        voter.setProcessDomainObjectClass(NomCity.class);
        return voter;
    

    @Bean
    AclEntryVoter aclUpdateVoter()
    
        return new AclEntryVoter(aclService(),"ACL_NOMCITY_UPDATE", new   Permission[]BasePermission.ADMINISTRATION);
    

    @Bean
    AclEntryVoter aclReadVoter()
    
        return new AclEntryVoter(aclService(),"ACL_NOMCITY_READ", new   Permission[]BasePermission.READ);
    

    @Bean
    AccessDecisionManager accessDecisionManager ()

        List<AccessDecisionVoter<? extends Object>> list = new ArrayList<>();
        list.add(aclDeleteVoter());
        list.add(aclReadVoter());
        list.add(aclUpdateVoter());
        return new AffirmativeBased(list);
    


我有以下 RestController 的方法,它使用前面定义的 ACL:

@RequestMapping(value = "/nomCitys",
        method = RequestMethod.POST,
        produces = MediaType.APPLICATION_JSON_VALUE)
@Timed
@Transactional
@Secured("ROLE_ADMIN","ROLE_USER")
public ResponseEntity<NomCity> create(@Valid @RequestBody NomCity nomCity) throws URISyntaxException 

    NomCity result = nomCityRepository.save(nomCity);

    User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    ObjectIdentity oi = new ObjectIdentityImpl(NomCity.class,result.hashCode());
    MutableAcl acl = mutableAclService.createAcl(oi);

    acl.insertAce(0, BasePermission.ADMINISTRATION, new GrantedAuthoritySid("ROLE_ADMIN"), true);
    acl.insertAce(1, BasePermission.DELETE, new PrincipalSid(user.getUsername()), true); 
    acl.insertAce(2, BasePermission.READ, new GrantedAuthoritySid("ROLE_USER"), true);

    mutableAclService.updateAcl(acl);

    return ResponseEntity.created(new URI("/api/nomCitys/" + result.getId()))
            .headers(HeaderUtil.createEntityCreationAlert("nomCity", result.getId().toString()))
            .body(result);

当我创建一个新城市时,也会创建以下 ACL 条目:

具有 ROLE_ADMIN 角色的用户具有管理员权限。 创建城市的用户拥有删除权限。 具有 ROLE_USER 角色的用户可以读取城市。

以下方法为删除方法:

@RequestMapping(value = "/nomCitys/id",
        method = RequestMethod.DELETE,
        produces = MediaType.APPLICATION_JSON_VALUE)
@Timed
@Transactional
@Secured("ACL_NOMCITY_DELETE")
public ResponseEntity<Void> delete(@PathVariable Long id) 

    nomCityRepository.delete(id);

    ObjectIdentity oid = new ObjectIdentityImpl(NomCity.class,id);
    mutableAclService.deleteAcl(oid, true);

    return ResponseEntity.ok().headers(HeaderUtil.createEntityDeletionAlert("nomCity", id.toString())).build();

当我创建一个新城市时,一切正常,ACL 条目被创建并存储在数据库中,但是当我去删除一个城市时,我得到一个 403,尽管我使用创建城市的用户登录,查看一些页面我看到了以下 xml 条目:

<security:global-method-security
  secured-annotations="enabled" access-decision-manager  ref="customAccessDecisionManager" />

我想它注册了 AccessDecisionManager,但我不知道如何使用 Java Config 做同样的事情,如果这是我所有问题的原因,我不知道。

【问题讨论】:

【参考方案1】:

这个问题是针对@secure 注释的,但我终于解决了这个问题,为使用@Pre 和@Post 注释做一个类配置,我在这个question 的答案中发布了一个配置java 类。

【讨论】:

以上是关于Spring Security 的 ACL 配置问题的主要内容,如果未能解决你的问题,请参考以下文章

Spring Security 中的访问总是被拒绝 - DenyAllPermissionEvaluator

spring security acl 不比较按位权限

Spring Security Acl 对象

非所有者时 Spring Security 更新 acl

Spring Security - ACL readAclsById 不按 SID 过滤

Spring Security ACL 层次结构