首先,我是Java Spring Framework的新手。如果我没有提供足够的信息,请原谅我。我试图将RoleHierarchy添加到我的应用程序中,但它不起作用。以下是我尝试的代码。
SecurityConfig.java
// These config is try to set up a user Role Hierarchy
@Bean
public RoleHierarchy roleHierarchy() {
System.out.println("arrive public RoleHierarchy roleHierarchy()");
RoleHierarchyImpl r = new RoleHierarchyImpl();
r.setHierarchy("ROLE_ADMIN > ROLE_STAFF");
r.setHierarchy("ROLE_STAFF > ROLE_USER");
r.setHierarchy("ROLE_DEVELOPER > ROLE_USER");
r.setHierarchy("ROLE_USER > ROLE_GUEST");
return r;
}
@Bean
public AffirmativeBased defaultAccessDecisionManager(RoleHierarchy roleHierarchy){
System.out.println("arrive public AffirmativeBased defaultAccessDecisionManager()");
List<AccessDecisionVoter> decisionVoters = new ArrayList<>();
// webExpressionVoter
WebExpressionVoter webExpressionVoter = new WebExpressionVoter();
DefaultWebSecurityExpressionHandler
expressionHandler = new DefaultWebSecurityExpressionHandler();
expressionHandler.setRoleHierarchy(roleHierarchy);
webExpressionVoter.setExpressionHandler(expressionHandler);
decisionVoters.add(webExpressionVoter);
decisionVoters.add(roleHierarchyVoter(roleHierarchy));
// return new AffirmativeBased(Arrays.asList((AccessDecisionVoter) webExpressionVoter));
return new AffirmativeBased(decisionVoters);
}
@Bean
public RoleHierarchyVoter roleHierarchyVoter(RoleHierarchy roleHierarchy) {
System.out.println("arrive public RoleHierarchyVoter roleHierarchyVoter");
return new RoleHierarchyVoter(roleHierarchy);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// skipping some codes
http
// skipping some codes
.accessDecisionManager(defaultAccessDecisionManager(roleHierarchy()))
// skipping some codes
}
MethodSecurityConfig.java
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
@Inject
private SecurityConfig securityConfig;
@Override
protected AuthenticationManager authenticationManager() throws Exception {
return securityConfig.authenticationManagerBean();
}
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
System.out.println("arrive protected MethodSecurityExpressionHandler createExpressionHandler()");
DefaultMethodSecurityExpressionHandler d = new DefaultMethodSecurityExpressionHandler();
d.setRoleHierarchy(securityConfig.roleHierarchy());
return d;
}
}
我有UserDetailsServiceImpl implements UserDetailsService
提供principal
,Authentication
和GrantedAuthority
最后我有一些API:
@PreAuthorize("hasRole('ROLE_STAFF')")
@RequestMapping(value = "/api/v1/contactUs", method = RequestMethod.GET)
@PreAuthorize("hasRole('ROLE_DEVELOPER')")
@RequestMapping(value = "/api/v1/system", method = RequestMethod.GET)
现在问题是如果我以ROLE_STAFF,ROLE_DEVELOPER,ROLE_ADMIN身份登录,我得到以下结果。
| API | ROLE_STAFF | ROLE_DEVELOPER | ROLE_ADMIN |
|-----------|------------|----------------|------------|
| contactUs | 200 | 403 | 403 |
| system | 403 | 200 | 403 |
正如您所见,ROLE_STAFF
和ROLE_DEVELOPER
工作正常。但是我希望ROLE_ADMIN
作为两者的超级角色而且它没有用。
仅供参考,我使用的是spring-security 3.2.5.RELEASE
答案 0 :(得分:15)
问题出在RoleHierachy中,它应该是这样的:
@Bean
public RoleHierarchy roleHierarchy() {
RoleHierarchyImpl r = new RoleHierarchyImpl();
r.setHierarchy("ROLE_ADMIN > ROLE_STAFF and ROLE_ADMIN > ROLE_DEVELOPER and ROLE_STAFF > ROLE_USER and ROLE_DEVELOPER > ROLE_USER");
return r;
}
保持通话setHierarchy()
将覆盖
答案 1 :(得分:12)
每次我想用Spring Security和Java配置实现角色层次结构时,我都使用以下方法:
我们必须在上下文中添加 RoleHierarchyImpl bean(您看,我使用多个角色来构建层次结构):
@Bean
public RoleHierarchyImpl roleHierarchy() {
RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
roleHierarchy.setHierarchy("ROLE_ADMIN > ROLE_DBA ROLE_DBA > ROLE_USER ");
return roleHierarchy;
}
然后我们需要创建Web表达式处理程序以将获得的层次结构传递给它:
private SecurityExpressionHandler<FilterInvocation> webExpressionHandler() {
DefaultWebSecurityExpressionHandler defaultWebSecurityExpressionHandler = new DefaultWebSecurityExpressionHandler();
defaultWebSecurityExpressionHandler.setRoleHierarchy(roleHierarchy());
return defaultWebSecurityExpressionHandler;
}
最后一步是将expressionHandler添加到http.authorizeRequests()中:
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.expressionHandler(webExpressionHandler())
.antMatchers("/admin/**").access("(hasRole('ROLE_ADMIN') or hasRole('ROLE_DBA')) and isFullyAuthenticated()")
.antMatchers("/dba").access("hasRole('ROLE_DBA') and isFullyAuthenticated()")
.antMatchers("/dba/**").access("hasRole('ROLE_USER')")
.and()
.requiresChannel()
.antMatchers("/security/**").requiresSecure()
.anyRequest().requiresInsecure()
.and()
.formLogin()
.loginPage("/login")
.failureUrl("/login?auth=fail")
.usernameParameter("username")
.passwordParameter("password")
.defaultSuccessUrl("/admin")
.permitAll()
.and()
.logout()
.logoutUrl("/logout")
.deleteCookies("remember-me")
.invalidateHttpSession(true)
.logoutSuccessUrl("/index")
.permitAll()
.and()
.csrf()
.and()
.rememberMe().tokenValiditySeconds(1209600)
.and()
.exceptionHandling().accessDeniedPage("/403")
.and()
.anonymous().disable()
.addFilter(switchUserFilter());
}
结果:在此特定示例中,我们尝试使用管理员用户(ROLE_ADMIN)登录后访问 / dba 部分。在我们创建层次结构之前,我们有一个访问被拒绝的结果,但现在我们可以毫无问题地访问此部分。
答案 2 :(得分:4)
注意:可接受的答案在最新版本的Spring安全性中不起作用(我认为自5.2.1版本以来)。 这是因为'and'表示法(ROLE_1> ROLE_2 and ROLE_2> ROLE_3)从来不是官方标准。您可以写出每个单词而不是'and',并且在过去的版本中仍然可以使用相同的语言。
相反,在新版本中,您现在应该使用“ \ n”(换行),例如ROLE_1> ROLE_2 \ nROLE2> ROLE_3 ...
答案 3 :(得分:0)
重写createExpressionHandler
方法,使其返回已配置的全局表达式处理程序
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class GlobalMethodSecurityConfig extends GlobalMethodSecurityConfiguration {
@Autowired
private RoleHierarchy roleHierarchy;
@Override
protected MethodSecurityExpressionHandler createExpressionHandler(){
return methodSecurityExpressionHandler();
}
private DefaultMethodSecurityExpressionHandler methodSecurityExpressionHandler(){
DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
expressionHandler.setRoleHierarchy(roleHierarchy);
return expressionHandler;
}
@Bean
public RoleHierarchyImpl roleHierarchy() {
RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
roleHierarchy.setHierarchy("ROLE_ADMIN > ROLE_OWNER > ROLE_USER");
return roleHierarchy;
}
@Bean
public RoleHierarchyVoter roleVoter() {
return new RoleHierarchyVoter(roleHierarchy);
}
@Configuration
public static class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {}
}
}
答案 4 :(得分:0)
对我来说,解决方案是为DefaultWebSecurityExpressionHandler
的实例提供了正确的bean名称。名称应为webSecurityExpressionHandler
。
@Bean
public RoleHierarchyImpl roleHierarchy() {
RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
roleHierarchy.setHierarchy(Roles.getRoleHierarchy());
return roleHierarchy;
}
@Bean
public DefaultWebSecurityExpressionHandler webSecurityExpressionHandler() {
DefaultWebSecurityExpressionHandler expressionHandler = new DefaultWebSecurityExpressionHandler();
expressionHandler.setRoleHierarchy(roleHierarchy());
return expressionHandler;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.expressionHandler(webSecurityExpressionHandler())
...
}
答案 5 :(得分:-2)
我不使用Spring RoleHierarchy - 因为它对我不起作用。 但Ussualy我喜欢这样: 定义角色界面
public static interface Role {
String getName();
List<String> getHierarchy();
}
我的角色列表(存储在数据库中):
public interface AuthStates {
// Spring security works fine only with ROLE_*** prefix
String ANONYMOUS = "ROLE_ANONYMOUS";
String AUTHENTICATED = "ROLE_AUTHENTICATED";
String ADMINISTRATOR = "ROLE_ADMINISTRATOR";
}
将匿名角色定义为基本角色类:
public static class Anonymous implements Role {
private final String name;
private final List<String> hierarchy = Lists.newArrayList(ANONYMOUS);
public Anonymous() {
this(ANONYMOUS);
}
protected Anonymous(String name) {
this.name = name;
}
@Override
public String getName() {
return name;
}
@Override
public List<String> getHierarchy() {
return hierarchy;
}
protected void addHierarchy(String name) {
hierarchy.add(name);
}
}
定义经过身份验证的角色(常见用户角色):
public static class Authenticated extends Anonymous {
public Authenticated() {
this(AUTHENTICATED);
}
protected Authenticated(String name) {
super(name);
addHierarchy(AUTHENTICATED);
}
}
定义管理员角色(在演变的顶部):
public static class Administrator extends Authenticated {
public Administrator() {
this(ADMINISTRATOR);
}
protected Administrator(String name) {
super(name);
addHierarchy(ADMINISTRATOR);
}
}
可选 - 静态工厂类:
public static Role getRole(String authState) {
switch (authState) {
case ANONYMOUS: return new Anonymous();
case AUTHENTICATED: return new Authenticated();
case ADMINISTRATOR: return new Administrator();
default: throw new IllegalArgumentException("Wrong auth state");
}
}
在我的CustomUserDetailsService(实现UserDetailsService)中,我使用这样的角色:
private Collection<GrantedAuthority> createAuthority(User user) {
final List<GrantedAuthority> authorities = new ArrayList<>();
AuthStates.Role userAuthState = AuthStates.getRole(user.getAuthState());
for (String role : userAuthState.getHierarchy()) {
authorities.add(new SimpleGrantedAuthority(role));
}
return authorities;
}
在控制器中:
@PreAuthorize("hasRole('ROLE_AUTHENTICATED')")
允许用户以ROLE_AUTHENTICATED和ROLE_ADMINISTRATOR身份登录。