gpt4 book ai didi

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

转载 作者:IT老高 更新时间:2023-10-28 13:51:05 27 4
gpt4 key购买 nike

我已经在我的 Spring Boot 应用程序中配置了 ACL。 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();
}
}

我的 CustomAuthenticationProvider 类:

@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);
}
}

这是我的 CustomUsernamePasswordAuthenticationToken:

public class CustomUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException {

if(!request.getMethod().equals("POST"))
throw new AuthenticationServiceException(String.format("Authentication method not supported: %s", request.getMethod()));

try {

CustomUsernamePasswordAuthenticationForm form = new ObjectMapper().readValue(request.getReader(), CustomUsernamePasswordAuthenticationForm.class);

String username = form.getUsername();
String password = form.getPassword();

if(username == null)
username = "";

if(password == null)
password = "";

UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, password);

setDetails(request, token);

return getAuthenticationManager().authenticate(token);

} catch (IOException exception) {
throw new CustomAuthenticationException(exception);
}
}

private class CustomAuthenticationException extends RuntimeException {
private CustomAuthenticationException(Throwable throwable) {
super(throwable);
}
}
}

除了上述之外,我还有 CustomAuthenticationFailureHandlerCustomAuthenticationSuccessHandlerCustomNoRedirectStrategyCustomUsernamePasswordAuthenticationForm考虑到这个问题的长度。

我正在使用 here 中的 MySQL 架构.

我正在向我的 acl 相关表中添加如下条目:

INSERT INTO acl_class VALUES (1, com.company.project.domain.users.User)
INSERT INTO acl_sid VALUES (1, 1, "demo")

(我有一个用户名为 demo 的用户)

INSERT INTO acl_object_identity VALUES (1, 1, 1, NULL, 1, 0)
INSERT INTO acl_entry VALUES (1, 1, 1, 1, 1, 1, 1, 1)

但我得到的只是:

Denying user demo permission 'READ' on object com.company.project.domain.users.User@4a49e9b4

在我的

@PostFilter("hasPermission(filterObject, 'READ')")

我怀疑这里有几个问题:

  1. hasPermission 表达式:我已将其替换为 'READ' 和 '1',但没有任何程度。
  2. 我的数据库条目不正确
  3. 我没有实现自定义权限评估器。这是必需的,还是 expressionHandler.setPermissionEvaluator(new 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);
}

更新 #2:

问题现在反射(reflect)了有关身份验证/授权/ACL 的所有设置。

更新 #3:

我现在非常接近解决这个问题,唯一剩下的就是解决这个问题:

https://stackoverflow.com/questions/42996579/custom-permissionevaluator-not-called-although-set-as-permissionevaluator-deny

如果有人可以帮助我解决这个问题,我终于可以写下我为解决这个问题所经历的事情了。

最佳答案

我升级了我的应用程序以使用 Spring Security 4.2.1.RELEASE,然后我开始在所有 @PreAuthorize 注释方法中遇到意外访问被拒绝,这在升级之前工作得很好。我调试了 spring 安全代码,我意识到问题是所有要检查的角色都以默认字符串“ROLE_”作为前缀,而不管我将默认前缀设置为空,如下面的代码所示。

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);

我所有的 Controller 方法都用 @PreAuthorize("hasRole('my_ldap_group_name')") 注释,但是,框架没有考虑我的空角色前缀设置,因此它使用 < em>ROLE_my_ldap_group_name 改为检查实际角色。

在深入研究了框架的代码之后,我意识到类 org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler 的默认角色前缀仍然设置为 "ROLE_ "。我跟进了它的值的来源,我发现它首先检查类 org.springframework.security.config.core.GrantedAuthorityDefaults 的声明 bean 以在第一次查找默认前缀bean org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer 的初始化,然而,由于这个初始化器 bean 找不到它声明,它最终使用了前面提到的默认前缀。

我认为这不是预期的行为:Spring Security 应该考虑与 ldapAuthentication 相同的 rolePrefix,但是,为了解决这个问题,有必要添加 bean org.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 GrantedAuthorityDefaults,所以如果你使用与我相同的 Spring Security 版本 - 4.2.1.RELEASE 你是可能会遇到同样的问题。

关于java - Spring Security 中的访问总是被拒绝 - DenyAllPermissionEvaluator,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41872192/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com