Spring Boot + Spring Безопасность + иерархические роли
Я пытаюсь настроить иерархические роли в моем загрузочном приложении Spring без успеха. Я сделал все, что было сказано в разных местах в Интернете. Но ни один из них не смог решить проблему.
Вот код моего класса SecurityConfig. Когда я вхожу в приложение с пользователем с ROLE_ADMIN, он должен иметь возможность извлекать данные из "/users", но в настоящее время я получаю исключение, связанное с доступом. Если у пользователя есть учетные данные ROLE_USER, он работает нормально.
Может ли кто-нибудь помочь мне понять, что не удается?
Заранее спасибо.
@Configuration
@EnableWebMvcSecurity
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private SigpaUserDetailsService userDetailsService;
@Bean
public RoleHierarchyImpl roleHierarchy() {
RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
roleHierarchy.setHierarchy("ROLE_ADMIN > ROLE_USER");
return roleHierarchy;
}
@Bean
public RoleHierarchyVoter roleVoter() {
return new RoleHierarchyVoter(roleHierarchy());
}
@Bean
public DefaultWebSecurityExpressionHandler expressionHandler(){
DefaultWebSecurityExpressionHandler expressionHandler = new DefaultWebSecurityExpressionHandler();
expressionHandler.setRoleHierarchy(roleHierarchy());
return expressionHandler;
}
@Bean
@SuppressWarnings(value = { "rawtypes" })
public AffirmativeBased accessDecisionManager() {
List<AccessDecisionVoter> decisionVoters = new ArrayList<AccessDecisionVoter>();
WebExpressionVoter webExpressionVoter = new WebExpressionVoter();
webExpressionVoter.setExpressionHandler(expressionHandler());
decisionVoters.add(webExpressionVoter);
decisionVoters.add(roleVoter());
return new AffirmativeBased(decisionVoters);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.accessDecisionManager(accessDecisionManager())
.expressionHandler(expressionHandler())
.antMatchers("/users/**")
.access("hasRole('ROLE_USER')")
.anyRequest().authenticated();
http
.formLogin()
.loginPage("/login").permitAll()
.and()
.logout()
.permitAll();
}
@Override
protected void configure(AuthenticationManagerBuilder registry)
throws Exception {
registry.userDetailsService(userDetailsService);
}
}
Обновление: Вот код, обновленный с вашим предложением, но все еще не работает.
Ответы
Ответ 1
Я только что прошел через эти настройки, так что, безусловно, ты будешь работать сейчас. Вот сделка:
Вы внесли эту аннотацию @EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
, но не указали какой-либо код для использования Pre/Post Authorize/Filter, поэтому я не знаю, действительно ли вам это нужно.
-
Если вам не нужна безопасность/фильтрация уровня класса/метода, все, что вам нужно сделать, это:
@Bean
public RoleHierarchyImpl roleHierarchy() {
RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
roleHierarchy.setHierarchy("ROLE_ADMIN > ROLE_USER");
return roleHierarchy;
}
и
private SecurityExpressionHandler<FilterInvocation> webExpressionHandler() {
DefaultWebSecurityExpressionHandler defaultWebSecurityExpressionHandler = new DefaultWebSecurityExpressionHandler();
defaultWebSecurityExpressionHandler.setRoleHierarchy(roleHierarchy());
return defaultWebSecurityExpressionHandler;
}
http
.authorizeRequests()
.expressionHandler(webExpressionHandler())
Вам не нужно переопределять свой собственный accessDecisionManager, если вам нужно только ввести иерархию ролей.
-
Если вам также нужна безопасность уровня класса/метода, т.е. используя PreAuthorize, PostAuthorize, PreFilter, PostFilter
в ваших методах/классах, то также создайте @Configuration, как это в вашем пути к классам (и удалите аннотацию @EnableGlobalMethodSecurity из вашего класса GlobalMethodSecurityConfig):
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class AnyNameYouLike extends GlobalMethodSecurityConfiguration {
@Resource
private RoleHierarchy roleHierarchy;
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
DefaultMethodSecurityExpressionHandler expressionHandler = (DefaultMethodSecurityExpressionHandler) super.createExpressionHandler();
expressionHandler.setRoleHierarchy(roleHierarchy);
return expressionHandler;
}
}
Я бы дал имя GlobalMethodSecurityConfig этому новому классу и изменил ваш текущий класс GlobalMethodSecurityConfig на WebSecurityConfig или что-то, что отразится на настройке безопасности для веб-уровня.
Я определяю RoleHierarchy
bean в webSecurityConfig и внедряю/использую его в globalMethodSecurityConfig, но вы можете сделать это любым способом, если вы не создаете 2 beans без необходимости.
Надеюсь, что это поможет.
Ответ 2
Вам нужно установить иерархию роли в элементе голосования веб-выражения. Что-то вроде:
DefaultWebSecurityExpressionHandler expressionHandler = new DefaultWebSecurityExpressionHandler();
expressionHandler.setRoleHierarchy(roleHierarchy);
webExpressionVoter.setExpressionHandler(expressionHandler);
Обновление: Вы также можете попробовать настроить обработчик вышеуказанного выражения следующим образом:
http
.authorizeRequests()
.expressionHandler(expressionHandler)
...
Ответ 3
Вы должны установить иерархию роли в MethodSecurityExpressionHandler:
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public static class GlobalMethodSecurityConfig extends GlobalMethodSecurityConfiguration {
@Autowired
private RoleHierarchy roleHierarchy;
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
final DefaultMethodSecurityExpressionHandler handler = new DefaultMethodSecurityExpressionHandler();
handler.setRoleHierarchy(this.roleHierarchy);
return handler;
}
}
За дополнительной информацией обращайтесь Javadoc для @EnableGlobalMethodSecurity. Особенно отметим: , что EnableGlobalMethodSecurity по-прежнему должны быть включены в класс, расширяющий GlobalMethodSecurityConfiguration, чтобы определить настройки.
Ответ 4
Включить защиту на уровне метода (т.е. @EnableGlobalMethodSecurity (prePostEnabled = true)) вместе с поддержкой Hierarchical-role в WebSecurityConfigurerAdapter.
1. Просто нужно отделить RoleHierarchy от любого другого класса, помеченного @Bean
2. Введите его, используя @Autowired на WebSecurityConfigurerAdapter. Это работает безупречно на моих проектах.
Пожалуйста, посмотрите на мой код.
WeSecurityConfig.class
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
public class AppSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private RoleHierarchy roleHierarchy;
private SecurityExpressionHandler<FilterInvocation> webExpressionHandler() {
DefaultWebSecurityExpressionHandler defaultWebSecurityExpressionHandler = new DefaultWebSecurityExpressionHandler();
defaultWebSecurityExpressionHandler.setRoleHierarchy(roleHierarchy);
return defaultWebSecurityExpressionHandler;
}
@Override
public void configure(WebSecurity web) throws Exception {
super.configure(web);
web.ignoring().antMatchers("/static/**");
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.
authorizeRequests()
.expressionHandler(webExpressionHandler())
.antMatchers("/static/**","/bower_components/**","/").permitAll()
.antMatchers("/user/login","/user/login?error").anonymous()
.anyRequest().authenticated()
.and()
.formLogin().loginPage("/user/login").passwordParameter("password").usernameParameter("username")
.defaultSuccessUrl("/")
.permitAll()
.and()
.logout().logoutUrl("/user/logout")
.logoutSuccessUrl("/user/login?logout")
.and().csrf();
}
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(daoAuthenticationProvider());
}
public DaoAuthenticationProvider daoAuthenticationProvider(){
final DaoAuthenticationProvider auth = new DaoAuthenticationProvider();
auth.setUserDetailsService(userDetailService);
auth.setPasswordEncoder(passwordEncoder);
return auth;
}
}
BeanConfiguration.class
@Configuration
public class BeanConfiguration {
@Bean
public RoleHierarchy roleHierarchy() {
RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
/* tricks lies here */
roleHierarchy.setHierarchy("ROLE_SUPREME > ROLE_ADMIN ROLE_ADMIN > ROLE_OPERATOR ROLE_OPERATOR > ROLE_GUEST");
return roleHierarchy;
}
}
Надеюсь, это поможет вам.