Java 在Spring Security-DenyAllPermissionEvaluator中始终拒绝访问
我已经在Spring Boot应用程序中配置了ACL。ACL配置如下所示:Java 在Spring Security-DenyAllPermissionEvaluator中始终拒绝访问,java,spring,spring-boot,spring-security,acl,Java,Spring,Spring Boot,Spring Security,Acl,我已经在Spring Boot应用程序中配置了ACL。ACL配置如下所示: @Configuration @ComponentScan(basePackages = "com.company") @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true) public class ACLConfigration extends GlobalMethodSecurityConfiguration {
@Configuration
@ComponentScan(basePackages = "com.company")
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class ACLConfigration extends GlobalMethodSecurityConfiguration {
@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_ACL_ADMIN"));
}
@Bean
public LookupStrategy lookupStrategy() {
return new BasicLookupStrategy(dataSource, aclCache(), aclAuthorizationStrategy(), new ConsoleAuditLogger());
}
@Bean
public JdbcMutableAclService aclService() {
return new JdbcMutableAclService(dataSource, lookupStrategy(), aclCache());
}
@Bean
public DefaultMethodSecurityExpressionHandler defaultMethodSecurityExpressionHandler() {
return new DefaultMethodSecurityExpressionHandler();
}
@Override
public MethodSecurityExpressionHandler createExpressionHandler() {
DefaultMethodSecurityExpressionHandler expressionHandler = defaultMethodSecurityExpressionHandler();
expressionHandler.setPermissionEvaluator(new AclPermissionEvaluator(aclService()));
expressionHandler.setPermissionCacheOptimizer(new AclPermissionCacheOptimizer(aclService()));
return expressionHandler;
}
}
@Configuration
@EnableWebSecurity
public class CustomSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Bean
public AuthenticationEntryPoint entryPoint() {
return new LoginUrlAuthenticationEntryPoint("/authenticate");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.authorizeRequests()
.antMatchers("/authenticate/**").permitAll()
.anyRequest().fullyAuthenticated()
.and().requestCache().requestCache(new NullRequestCache())
.and().addFilterBefore(authenticationFilter(), CustomUsernamePasswordAuthenticationFilter.class);
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers(HttpMethod.OPTIONS, "/**");
}
@Bean
public CustomUsernamePasswordAuthenticationFilter authenticationFilter()
throws Exception {
CustomUsernamePasswordAuthenticationFilter authenticationFilter = new CustomUsernamePasswordAuthenticationFilter();
authenticationFilter.setUsernameParameter("username");
authenticationFilter.setPasswordParameter("password");
authenticationFilter.setFilterProcessesUrl("/authenticate");
authenticationFilter.setAuthenticationSuccessHandler(new CustomAuthenticationSuccessHandler());
authenticationFilter.setAuthenticationFailureHandler(new CustomAuthenticationFailureHandler());
authenticationFilter.setAuthenticationManager(authenticationManagerBean());
return authenticationFilter;
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
INSERT INTO acl_class VALUES (1, com.company.project.domain.users.User)
INSERT INTO acl_sid VALUES (1, 1, "demo")
参考资料:
@Configuration
@ComponentScan(basePackages = "com.company")
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class ACLConfigration extends GlobalMethodSecurityConfiguration {
@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_ACL_ADMIN"));
}
@Bean
public LookupStrategy lookupStrategy() {
return new BasicLookupStrategy(dataSource, aclCache(), aclAuthorizationStrategy(), new ConsoleAuditLogger());
}
@Bean
public JdbcMutableAclService aclService() {
return new JdbcMutableAclService(dataSource, lookupStrategy(), aclCache());
}
@Bean
public DefaultMethodSecurityExpressionHandler defaultMethodSecurityExpressionHandler() {
return new DefaultMethodSecurityExpressionHandler();
}
@Override
public MethodSecurityExpressionHandler createExpressionHandler() {
DefaultMethodSecurityExpressionHandler expressionHandler = defaultMethodSecurityExpressionHandler();
expressionHandler.setPermissionEvaluator(new AclPermissionEvaluator(aclService()));
expressionHandler.setPermissionCacheOptimizer(new AclPermissionCacheOptimizer(aclService()));
return expressionHandler;
}
}
@Configuration
@EnableWebSecurity
public class CustomSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Bean
public AuthenticationEntryPoint entryPoint() {
return new LoginUrlAuthenticationEntryPoint("/authenticate");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.authorizeRequests()
.antMatchers("/authenticate/**").permitAll()
.anyRequest().fullyAuthenticated()
.and().requestCache().requestCache(new NullRequestCache())
.and().addFilterBefore(authenticationFilter(), CustomUsernamePasswordAuthenticationFilter.class);
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers(HttpMethod.OPTIONS, "/**");
}
@Bean
public CustomUsernamePasswordAuthenticationFilter authenticationFilter()
throws Exception {
CustomUsernamePasswordAuthenticationFilter authenticationFilter = new CustomUsernamePasswordAuthenticationFilter();
authenticationFilter.setUsernameParameter("username");
authenticationFilter.setPasswordParameter("password");
authenticationFilter.setFilterProcessesUrl("/authenticate");
authenticationFilter.setAuthenticationSuccessHandler(new CustomAuthenticationSuccessHandler());
authenticationFilter.setAuthenticationFailureHandler(new CustomAuthenticationFailureHandler());
authenticationFilter.setAuthenticationManager(authenticationManagerBean());
return authenticationFilter;
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
INSERT INTO acl_class VALUES (1, com.company.project.domain.users.User)
INSERT INTO acl_sid VALUES (1, 1, "demo")
MyCustomAuthenticationProvider
class:
@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
@Autowired
private UsersService usersService;
@Override
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
String username = authentication.getName();
String password = authentication.getCredentials().toString();
User user = usersService.findOne(username);
if(user != null && usersService.comparePassword(user, password)){
return new UsernamePasswordAuthenticationToken(
user.getUsername(),
user.getPassword(),
AuthorityUtils.commaSeparatedStringToAuthorityList(
user.getUserRoles().stream().collect(Collectors.joining(","))));
} else {
return null;
}
}
@Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}
除上述内容外,我还有CustomAuthenticationFailureHandler
、CustomAuthenticationSuccessHandler
、CustomNoRedirectStrategy
和customusernamespasswordauthenticationform
,由于这个问题的长度,我跳过了这些内容
我使用的是可以找到的MySQL模式
我正在向acl相关表中添加条目,如下所示:
@Configuration
@ComponentScan(basePackages = "com.company")
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class ACLConfigration extends GlobalMethodSecurityConfiguration {
@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_ACL_ADMIN"));
}
@Bean
public LookupStrategy lookupStrategy() {
return new BasicLookupStrategy(dataSource, aclCache(), aclAuthorizationStrategy(), new ConsoleAuditLogger());
}
@Bean
public JdbcMutableAclService aclService() {
return new JdbcMutableAclService(dataSource, lookupStrategy(), aclCache());
}
@Bean
public DefaultMethodSecurityExpressionHandler defaultMethodSecurityExpressionHandler() {
return new DefaultMethodSecurityExpressionHandler();
}
@Override
public MethodSecurityExpressionHandler createExpressionHandler() {
DefaultMethodSecurityExpressionHandler expressionHandler = defaultMethodSecurityExpressionHandler();
expressionHandler.setPermissionEvaluator(new AclPermissionEvaluator(aclService()));
expressionHandler.setPermissionCacheOptimizer(new AclPermissionCacheOptimizer(aclService()));
return expressionHandler;
}
}
@Configuration
@EnableWebSecurity
public class CustomSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Bean
public AuthenticationEntryPoint entryPoint() {
return new LoginUrlAuthenticationEntryPoint("/authenticate");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.authorizeRequests()
.antMatchers("/authenticate/**").permitAll()
.anyRequest().fullyAuthenticated()
.and().requestCache().requestCache(new NullRequestCache())
.and().addFilterBefore(authenticationFilter(), CustomUsernamePasswordAuthenticationFilter.class);
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers(HttpMethod.OPTIONS, "/**");
}
@Bean
public CustomUsernamePasswordAuthenticationFilter authenticationFilter()
throws Exception {
CustomUsernamePasswordAuthenticationFilter authenticationFilter = new CustomUsernamePasswordAuthenticationFilter();
authenticationFilter.setUsernameParameter("username");
authenticationFilter.setPasswordParameter("password");
authenticationFilter.setFilterProcessesUrl("/authenticate");
authenticationFilter.setAuthenticationSuccessHandler(new CustomAuthenticationSuccessHandler());
authenticationFilter.setAuthenticationFailureHandler(new CustomAuthenticationFailureHandler());
authenticationFilter.setAuthenticationManager(authenticationManagerBean());
return authenticationFilter;
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
INSERT INTO acl_class VALUES (1, com.company.project.domain.users.User)
INSERT INTO acl_sid VALUES (1, 1, "demo")
(我有一个用户名为demo
的用户)
但我得到的只是:
Denying user demo permission 'READ' on object com.company.project.domain.users.User@4a49e9b4
在我的
我在这里怀疑几个问题:
hasPermission
表达式:我已将其替换为'READ'和'1',但没有达到任何程度expressionHandler.setPermissionEvaluator(新的AclPermissionEvaluator(aclService())代码>够了吗
@PostFilter
的示例方法:
@RequestMapping(method = RequestMethod.GET)
@PostFilter("hasPermission(filterObject, 'READ')")
List<User> find(@Min(0) @RequestParam(value = "limit", required = false, defaultValue = "10") Integer limit,
@Min(0) @RequestParam(value = "page", required = false, defaultValue = "0") Integer page,
@RequestParam(value = "email", required = false) String email,
@RequestParam(value = "firstName", required = false) String firstName,
@RequestParam(value = "lastName", required = false) String lastName,
@RequestParam(value = "userRole", required = false) String userRole) {
return usersService.find(
limit,
page,
email,
firstName,
lastName,
userRole);
}
@RequestMapping(method=RequestMethod.GET)
@PostFilter(“hasPermission(filterObject,'READ')”)
列表查找(@Min(0)@RequestParam(value=“limit”,required=false,defaultValue=“10”)整数限制,
@最小值(0)@RequestParam(value=“page”,required=false,defaultValue=“0”)整数页,
@RequestParam(value=“email”,required=false)字符串电子邮件,
@RequestParam(value=“firstName”,required=false)字符串firstName,
@RequestParam(value=“lastName”,required=false)字符串lastName,
@RequestParam(value=“userRole”,required=false)字符串(userRole){
返回usersService.find(
极限,
页
电子邮件,
名字,
姓,
用户角色);
}
更新#2:
现在的问题反映了有关身份验证/授权/ACL的所有设置
更新#3:
我现在非常接近解决这个问题,唯一剩下的就是解决这个问题:
如果有人能帮我解决这个问题,我终于可以写一篇我解决这个问题的经历。我将我的应用程序升级为使用Spring Security 4.2.1.RELEASE,然后我开始在所有
@PreAuthorize
注释的方法中遇到意外的访问被拒绝,在升级之前,它工作得很好。
我调试了spring安全代码,发现问题是所有要检查的角色都以默认字符串“ROLE_uz”作为前缀,而不管我是否已将默认前缀设置为空,如下面的代码所示
auth.ldapAuthentication()
.groupSearchBase(ldapProperties.getProperty("groupSearchBase"))
.groupRoleAttribute(ldapProperties.getProperty("groupRoleAttribute"))
.groupSearchFilter(ldapProperties.getProperty("groupSearchFilter"))
//this call used to be plenty to override the default prefix
.rolePrefix("")
.userSearchBase(ldapProperties.getProperty("userSearchBase"))
.userSearchFilter(ldapProperties.getProperty("userSearchFilter"))
.contextSource(this.ldapContextSource);
所有我的控制器方法都用@PreAuthorize(“hasRole('my_ldap_group_name'))”
注释,但是,框架没有考虑我的空角色前缀设置,因此它使用角色\u我的ldap_group_name来检查实际的角色
在深入研究框架的代码之后,我意识到类org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler
仍然将默认角色前缀设置为“role\ux”
。我跟踪了它的值的来源,发现它首先检查类org.springframework.security.config.core.GrantedAuthorityDefaults
的声明bean,以便在bean的第一次初始化期间查找默认前缀org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer
,但是,由于此初始值设定项bean找不到它声明的值,它最终使用了前面提到的默认前缀
我相信这不是一个预期的行为:Spring安全性应该考虑与ldapAuthentication相同的rolePrefix,但是,为了解决这个问题,有必要将beanorg.springframework.Security.config.core.GrantedAuthorityDefaults
添加到我的应用程序上下文中(我使用的是基于注释的配置),详情如下:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class CesSecurityConfiguration extends WebSecurityConfigurerAdapter {
private static final String ROLE_PREFIX = "";
//... ommited code ...
@Bean
public GrantedAuthorityDefaults grantedAuthorityDefaults() {
return new GrantedAuthorityDefaults(ROLE_PREFIX);
}
}
也许你也遇到了同样的问题-我可以看到你使用的是DefaultMethodSecurityExpressionHandler,它还使用了bean授权的AuthorityDefaults,因此如果你使用的是与我相同的Spring安全版本-4.2.1.RELEASE,你可能会遇到同样的问题。你的数据库数据和配置看起来都不错。我一直使用
@PostFilter(“hasPermission(filterObject,'READ')”
我会检查以确保扩展UserDetails的用户类通过数据库中的getUsername()返回相同的用户名。同时检查以确保您的安全性和应用程序处于相同的上下文中
该方法将对象作为其第一个参数
boolean hasPermission(Authentication authentication,
Object targetDomainObject,
Object permission)
身份验证对象是一个实现类,通常为。因此getPrincipal()方法需要返回一个对象,该对象具有一个getUserName()方法,该方法返回与数据库中相同的内容
看看
这是等待已久的答案: 报告清楚地描述了: 要使用hasPermission()表达式,必须显式配置 应用程序上下文中的PermissionEvaluator。这看起来 大概是这样的: 所以基本上我是在我的
AclConfiguration
中进行的,它扩展了GlobalMethodSecurityConfiguration
:
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
expressionHandler.setPermissionEvaluator(new AclPermissionEvaluator(aclService()));
expressionHandler.setPermissionCacheOptimizer(new AclPermissionCacheOptimizer(aclService()));
return expressionHandler;
}
这不是由Spring处理的
我必须将AclConfig
和GlobalMethodSecurityConfiguration
分开。如果在后者中定义了@Bean
s,则不会处理上述方法,这可能会导致