java – Spring Boot中的ACL安全性
作者:互联网
我在Spring Boot应用程序中通过Java配置设置ACL时遇到问题.我创建了一个小项目来重现问题.
我尝试过几种不同的方法.我遇到的第一个问题是EhCache,在我修复之后(我假设我做了)我再也无法登录了,看起来所有的数据都消失了.
有4个类具有不同的配置:
ACLConfig1.class
ACLConfig2.class
ACLConfig3.class
ACLConfig4.class
所有@PreAuthorize和@PostAuthorize注释都按预期工作,但hasPermission除外.
控制器拥有4个端点:一个用于User,一个用于Admin,一个用于Public,最后一个让我头疼@PostAuthorize(“hasPermission(returnObject,’administration’)”)
我很确定DB中的插入是正确的.这个类是四个中的一个,也是我尝试过的最后一个类:
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class ACLConfig4 {
@Autowired
DataSource dataSource;
@Bean
public EhCacheBasedAclCache aclCache() {
return new EhCacheBasedAclCache(aclEhCacheFactoryBean().getObject(), permissionGrantingStrategy(), aclAuthorizationStrategy());
}
@Bean
public EhCacheFactoryBean aclEhCacheFactoryBean() {
EhCacheFactoryBean ehCacheFactoryBean = new EhCacheFactoryBean();
ehCacheFactoryBean.setCacheManager(aclCacheManager().getObject());
ehCacheFactoryBean.setCacheName("aclCache");
return ehCacheFactoryBean;
}
@Bean
public EhCacheManagerFactoryBean aclCacheManager() {
return new EhCacheManagerFactoryBean();
}
@Bean
public DefaultPermissionGrantingStrategy permissionGrantingStrategy() {
ConsoleAuditLogger consoleAuditLogger = new ConsoleAuditLogger();
return new DefaultPermissionGrantingStrategy(consoleAuditLogger);
}
@Bean
public AclAuthorizationStrategy aclAuthorizationStrategy() {
return new AclAuthorizationStrategyImpl(new SimpleGrantedAuthority("ROLE_ADMINISTRATOR"));
}
@Bean
public LookupStrategy lookupStrategy() {
return new BasicLookupStrategy(dataSource, aclCache(), aclAuthorizationStrategy(), new ConsoleAuditLogger());
}
@Bean
public JdbcMutableAclService aclService() {
JdbcMutableAclService service = new JdbcMutableAclService(dataSource, lookupStrategy(), aclCache());
return service;
}
@Bean
public DefaultMethodSecurityExpressionHandler defaultMethodSecurityExpressionHandler() {
return new DefaultMethodSecurityExpressionHandler();
}
@Bean
public MethodSecurityExpressionHandler createExpressionHandler() {
DefaultMethodSecurityExpressionHandler expressionHandler = defaultMethodSecurityExpressionHandler();
expressionHandler.setPermissionEvaluator(new AclPermissionEvaluator(aclService()));
expressionHandler.setPermissionCacheOptimizer(new AclPermissionCacheOptimizer(aclService()));
return expressionHandler;
}
}
我在这里错过了什么?如果我使用ACLConfig3.class或者为什么我没有数据
ACLConfig4.class.有没有关于如何在Spring Boot中以编程方式配置它的示例?
解决方法:
找不到你没有数据的原因有点棘手.只要在配置中定义MethodSecurityExpressionHandler bean,数据库表中就没有数据.这是因为您的data.sql文件未执行.
在解释为什么没有执行data.sql之前,我首先要指出你没有按预期使用该文件.
初始化hibernate后,spring.sboot执行data.sql,通常只包含DML语句.您的data.sql包含DDL(模式)语句和DML(数据)语句.这并不理想,因为一些DDL语句与hibernate的hibernate.hbm2ddl.auto行为发生冲突(请注意,当使用嵌入式DataSource时,spring-boot使用’create-drop’).您应该将您的DDL语句放在schema.sql中,将DML语句放在data.sql中.当您手动定义所有表时,应禁用hibernate.hbm2ddl.auto(通过将spring.jpa.hibernate.ddl-auto = none添加到applciation.properties).
话虽这么说,让我们来看看为什么没有执行data.sql.
data.sql的执行是通过一个通过BeanPostProcessor触发的ApplicationEvent触发的.这个BeanPostProcessor(DataSourceInitializedPublisher)是作为spring-boot的Hibernate / JPA自动配置的一部分创建的(请参阅org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,org.springframework.boot.autoconfigure.orm.jpa.DataSourceInitializedPublisher and org .springframework.boot.autoconfigure.jdbc.DataSourceInitializer).
通常,DataSourceInitializedPublisher是在创建(嵌入)DataSource之前创建的,并且一切都按预期工作,但通过定义自定义MethodSecurityExpressionHandler,正常的bean创建顺序会改变.
在配置@EnableGlobalMethodSecurity后,您将自动导入GlobalMethodSecurityConfiguration.
spring-security相关bean早期创建.由于您的MethodSecurityExpressionHandler需要ACL资源的数据源,并且与spring-security相关的bean需要您自定义的MethodSecurityExpressionHandler,因此DataSource比平常更早创建;事实上,它是在Spring-boot的DataSourceInitializedPublisher尚未创建的早期创建的.
DataSourceInitializedPublisher稍后创建,但由于它没有注意到DataSource bean的创建,因此它也不会触发data.sql的执行.
长话短说:安全配置改变了正常的bean创建顺序,导致data.sql没有被加载.
我想修复bean创建顺序可以解决这个问题,但是我现在不知道如何(没有进一步的实验)我提出以下解决方案:手动定义你的DataSource并负责数据初始化.
@Configuration
public class DataSourceConfig {
@Bean
public EmbeddedDatabase dataSource() {
return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2)
//as your data.sql file contains both DDL & DML you might want to rename it (e.g. init.sql)
.addScript("classpath:/data.sql")
.build();
}
}
由于data.sql文件包含应用程序所需的所有DDL,因此可以禁用hibernate.hbm2ddl.auto.将spring.jpa.hibernate.ddl-auto = none添加到applciation.properties.
定义自己的DataSource时,spring-boot的DataSourceAutoConfiguration通常会退出,但如果你想确定你也可以排除它(可选).
@SpringBootConfiguration
@EnableAutoConfiguration(exclude = DataSourceAutoConfiguration.class)
@ComponentScan
@EnableCaching
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
这应该可以解决您的“无数据”问题.但为了让一切按预期工作,您需要再进行2次修改.
首先,您应该只定义一个MethodSecurityExpressionHandler bean.目前,您正在定义2个MethodSecurityExpressionHandler bean. Spring-security不会知道使用哪一个,而是(默默地)使用它自己的内部MethodSecurityExpressionHandler.请参阅org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration #setMethodSecurityExpressionHandler.
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class MyACLConfig {
//...
@Bean
public MethodSecurityExpressionHandler createExpressionHandler() {
DefaultMethodSecurityExpressionHandler securityExpressionHandler = new DefaultMethodSecurityExpressionHandler();
securityExpressionHandler.setPermissionEvaluator(new AclPermissionEvaluator(aclService()));
securityExpressionHandler.setPermissionCacheOptimizer(new AclPermissionCacheOptimizer(aclService()));
return securityExpressionHandler;
}
}
您需要做的最后一件事是将Car中的getId()方法设为public.
@Entity
public class Car {
//...
public long getId() {
return id;
}
//...
}
在尝试在ACL权限评估期间确定对象的标识时,标准ObjectIdentityRetrievalStrategy将查找公共方法’getId()’.
(请注意,我的答案基于ACLConfig4.)
标签:java,spring-security,spring-boot-2,spring-cache,acl 来源: https://codeday.me/bug/20190716/1475124.html