【发布时间】:2019-06-21 07:00:50
【问题描述】:
我已经通过以下方式实现了 Webflux 安全性:
- ReactiveUserDetailsService
- ReactiveAuthenticationManager
- ServerSecurityContextRepository
现在,我正在尝试按照此处的文档介绍 RoleHierarchy:Role Hierarchy Docs
我有一个角色为 USER 的用户,但他在点击带有 GUEST 角色注释的控制器时收到 403 Denied。角色层次结构为:“ROLE_ADMIN > ROLE_USER ROLE_USER > ROLE_GUEST”
@Configuration
@EnableWebFluxSecurity
@EnableReactiveMethodSecurity
public class SecurityConfig {
private final DaoAuthenticationManager reactiveAuthenticationManager;
private final SecurityContextRepository securityContextRepository;
private static final String ROLE_HIERARCHIES = "ROLE_ADMIN > ROLE_USER ROLE_USER > ROLE_GUEST";
@Autowired
public SecurityConfig(DaoAuthenticationManager reactiveAuthenticationManager,
SecurityContextRepository securityContextRepository) {
this.reactiveAuthenticationManager = reactiveAuthenticationManager;
this.securityContextRepository = securityContextRepository;
}
@Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
return http
.csrf().disable()
.formLogin().disable()
.httpBasic().disable()
.authenticationManager(reactiveAuthenticationManager)
.securityContextRepository(securityContextRepository)
.authorizeExchange()
.anyExchange().permitAll()
.and()
.logout().disable()
.build();
}
@Bean(name = "roleHierarchy")
public RoleHierarchy roleHierarchy() {
RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
roleHierarchy.setHierarchy(ROLE_HIERARCHIES);
return roleHierarchy;
}
@Bean(name = "roleVoter")
public RoleVoter roleVoter() {
return new RoleHierarchyVoter(roleHierarchy());
}
}
@Component
public class DaoAuthenticationManager implements ReactiveAuthenticationManager {
private final DaoUserDetailsService userDetailsService;
private final Scheduler scheduler;
@Autowired
public DaoAuthenticationManager(DaoUserDetailsService userDetailsService,
Scheduler scheduler) {
Assert.notNull(userDetailsService, "userDetailsService cannot be null");
this.userDetailsService = userDetailsService;
this.scheduler = scheduler;
}
@Override
public Mono<Authentication> authenticate(Authentication authentication) {
final String username = authentication.getName();
return this.userDetailsService.findByUsername(username)
.publishOn(this.scheduler)
.switchIfEmpty(
Mono.defer(() -> Mono.error(new UsernameNotFoundException("Invalid Username"))))
.map(u -> new UsernamePasswordAuthenticationToken(u, u.getPassword(),
u.getAuthorities()));
}
}
@Component
public class SecurityContextRepository implements ServerSecurityContextRepository {
private final DaoAuthenticationManager authenticationManager;
@Autowired
public SecurityContextRepository(DaoAuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
@Override
public Mono<Void> save(ServerWebExchange swe, SecurityContext sc) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public Mono<SecurityContext> load(ServerWebExchange swe) {
ServerHttpRequest request = swe.getRequest();
if (request.getHeaders().containsKey("userName") &&
!Objects.requireNonNull(request.getHeaders().get("userName")).isEmpty()) {
String userName = Objects.requireNonNull(swe
.getRequest()
.getHeaders()
.get("userName")).get(0);
Authentication auth = new UsernamePasswordAuthenticationToken(userName,
Security.PASSWORD);
return this.authenticationManager.authenticate(auth).map(SecurityContextImpl::new);
} else {
return Mono.empty();
}
}
}
无论如何要让角色层次结构在 Webflux 安全中起作用。
编辑
控制器:
@GetMapping
@PreAuthorize("hasRole('USER')")
public Mono<Device> getDevice(@RequestParam String uuid) {
return deviceService.getDevice(uuid);
}
普通角色授权对我有用,不工作的是层次结构部分。
【问题讨论】:
-
您也可以添加控制器代码吗?你是怎么注释的?我目前面临同样的问题,并找到了一个非常幼稚的解决方案。检查这篇文章,它可以对应于您注释控制器的方式:github.com/spring-projects/spring-security/issues/5046
-
顺便说一下你不需要定义和设置一个AuthenticationManager,你只需要定义你自己的
ReactiveUserDetailsService的Bean -
@LG_ 更新了我的帖子以添加控制器。我为
ReactiveUserDetailsService添加了一个实现,不知何故我的流程还需要ReactiveAuthenticationManager
标签: spring spring-boot spring-security spring-webflux