Spring Security ACL:我无法更新ACL

我正在尝试学习一些Spring Security ACL控件并将其应用于我的Spring Boot项目。因此,我尝试重用Spring Security参考中的代码片段,我对项目需求做了一些调整。


我具有以下组件,以便在启动时用一些初始值填充数据库。


@Component

public class AppBootstrap {


    private Authority adminAuth;

    private User admin;

    private TimeSheet timeSheetAdmin;


    private final JdbcMutableAclService jdbcMutableAclService;


    private final PlatformTransactionManager transactionManager;


    @Autowired

    public AppBootstrap(JdbcMutableAclService jdbcMutableAclService, PlatformTransactionManager transactionManager) {

        this.jdbcMutableAclService = jdbcMutableAclService;

        this.transactionManager = transactionManager;

    }


    @Bean

    public CommandLineRunner initialAuthorities(AuthorityRepository authorityRepository) {

        return args -> {

            adminAuth = new Authority(ROLE_ADMIN);

            authorityRepository.save(adminAuth);

        };

    }


    @Bean

    public CommandLineRunner initialUsers(UserRepository userRepository) {

        return args -> {

            admin = new User("admin",

                    "{bcrypt}$2a$08$lDnHPz7eUkSi6ao14Twuau08mzhWrL4kyZGGU5xfiGALO/Vxd5DOi", "admin",

                    "admin", "admin@example.com", true, getDate(2016, JANUARY, 1));

            admin.setAuthorities(asList(adminAuth));


            userRepository.save(admin);

        };

    }


    @Bean

    public CommandLineRunner initialTimeSheets(TimeSheetRepository timeSheetRepository) {

        return args -> {

            timeSheetAdmin = new TimeSheet(LocalDate.of(2016, MARCH, 1), admin);


            timeSheetRepository.save(timeSheetUser);

        };

    }


    @Bean

    public CommandLineRunner initialRights() {

        return args -> grantPermission(admin, timeSheetAdmin, ADMINISTRATION);

    }



每次刷新应用程序上下文时都会运行此方法。我可以看到,如果仅运行一种测试方法(或测试类),则该方法将成功运行。这些测试是端到端测试(@RunWith(SpringRunner.class) @SpringBootTest)。另外,@SpringBootApplication独自一人也没问题。但是,如果我一次运行所有测试,@SpringBootTest则以下堆栈跟踪几乎都失败了

我有一些问题:

  • 当我运行多个测试类时,为什么会发生此错误?

  • 如何找到解决方法?有没有更好的方法可以实现相同目的?


繁华开满天机
浏览 230回答 2
2回答

慕侠2389804

我遇到过同样的问题。就我而言,ACL缓存脏了。每次测试后,我必须清除缓存,然后所有测试都以绿色运行,即使同时调用也是如此。我为此创建了一个TestExcutionListener。只需用它注释您的抽象Test类:@TestExecutionListeners(    value = ClearAclCacheTestExecutionListener.class,    mergeMode = TestExecutionListeners.MergeMode.MERGE_WITH_DEFAULTS) public class AbstractTest{...}public class ClearAclCacheTestExecutionListener extends AbstractTestExecutionListener {    @Autowired    private AclCache aclCache;    @Override    public void beforeTestClass(TestContext testContext) {        testContext.getApplicationContext()                .getAutowireCapableBeanFactory()                .autowireBean(this);    }    @Override    public void afterTestMethod(TestContext testContext) throws Exception {        super.afterTestMethod(testContext);        aclCache.clearCache();    }}

郎朗坤

由于这个问题并没有那么受欢迎,因此我尝试了一种不同的方法,该方法似乎非常有用:-)首先,我创建了一个新的ACLService类,以隔离与JdbcMutableAclService的所有交互。package com.roberto.security.service;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.security.acls.model.*;import org.springframework.stereotype.Service;/** * Service class to handle ACL permissions. */@Servicepublic class ACLService {    private final MutableAclService mutableAclService;    @Autowired    public ACLService(MutableAclService mutableAclService) {        this.mutableAclService = mutableAclService;    }    /**     * Insert an ACL entry     * @param oid represents the model object     * @param recipient represents the principal (user, group of users, etc)     * @param permission quite explicit name...     * @return the new ACL database entry     */    public MutableAcl addPermission(ObjectIdentity oid, Sid recipient, Permission permission) {        MutableAcl acl;        try {            acl = (MutableAcl) mutableAclService.readAclById(oid);        } catch (NotFoundException nfe) {            acl = mutableAclService.createAcl(oid);        }        acl.insertAce(acl.getEntries().size(), permission, recipient, true);        return mutableAclService.updateAcl(acl);    }   }然后,我创建了另一个集成测试,该测试可以正常运行,而没有IllegalStateException。现在,我只需要从我的引导程序类中调用它即可。package com.roberto.security.service;import com.roberto.model.TimeSheet;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.security.acls.domain.BasePermission;import org.springframework.security.acls.domain.ObjectIdentityImpl;import org.springframework.security.acls.domain.PrincipalSid;import org.springframework.security.acls.model.*;import org.springframework.security.test.context.support.WithUserDetails;import org.springframework.test.annotation.DirtiesContext;import org.springframework.test.context.junit4.SpringRunner;import org.springframework.transaction.annotation.Transactional;import java.util.List;import static org.junit.Assert.*;import static org.springframework.test.annotation.DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD;/** * This test handles basic interaction between our codebase * Spring Security ACL and the underlying database model */@SpringBootTest@RunWith(SpringRunner.class)public class ACLServiceIntegrationTest {    private Authentication authentication;    private ObjectIdentity oid ;    private Sid sid;    private Permission administration = BasePermission.ADMINISTRATION;    @Autowired    private ACLService aclService;    @Autowired    private MutableAclService mutableAclService;    @Autowired    private PermissionEvaluator permissionEvaluator;    @Before    public void setUp() {        authentication = TestSecurityContextHolder.getContext().getAuthentication();        sid = new PrincipalSid(((JwtUser) authentication.getPrincipal()).getUsername());        oid = new ObjectIdentityImpl(TimeSheet.class, 1);    }    @Test    @WithUserDetails("admin")    public void testBeans() {        assertNotNull(aclService);        assertNotNull(mutableAclService);        assertNotNull(permissionEvaluator);    }    @Test    @Transactional    @WithUserDetails("admin")    @DirtiesContext(methodMode = AFTER_METHOD)    public void addPermissionIntegrationTest() {        assertFalse(permissionEvaluator.hasPermission(authentication, oid.getIdentifier(), oid.getType(), administration));        MutableAcl acl = aclService.addPermission(oi, sid, administration);        assertTrue(permissionEvaluator.hasPermission(authentication, oid.getIdentifier(), oid.getType(), administration));        assertEquals(TimeSheet.class.toString().split(" ")[1], acl.getObjectIdentity().getType());        assertTrue(acl.getEntries().stream().anyMatch(e -> e.getSid().equals(sid) && e.getPermission().equals(administration)));        assertTrue(acl.isGranted(List.of(administration), List.of(sid), true));    }}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java