当前位置: 首页 > 知识库问答 >
问题:

如何在Spring WebFlux中使用@PreAuthorize?

倪灿
2023-03-14

在Spring Web中,我使用@PreAuthorize with SpEl来检查当前用户的权限。类似这样的东西:

@Component
public class CustomSecurity {
    public boolean checkPermission(){
        Authentication authentication = SecurityContextHolder.getContext()
                .getAuthentication();
        CurrentAccount currentAccount = (CurrentAccount)authentication.getPrincipal();
        return currentAccount.getUsername().equals("admin");
    }
}

在RestController中:

@PreAuthorize("@customSecurity.checkPermission()")
@GetMapping("/")
public Object getWidgetValues() {
    return "Hello admin";
}

现在我尝试使用WebFlux。写入了reactiveCheckPermission。

public boolean checkPermission2() {
    return ReactiveSecurityContextHolder.getContext()
            .map(SecurityContext::getAuthentication)
            .map(Authentication::getPrincipal)
            .map(o -> (CurrentAccount) o)
            .map(currentAccount -> currentAccount.getUsername().equals("admin"))
            .block();
}

但是它抛出IllegalStateException("block()/block First()/block Final()是阻塞的,线程并行不支持

将boolean更改为Mono,但@PreAuthroze只需要boolean,而不需要Mono。

如何在WebFlux中使用@PreAuthorize?

共有2个答案

邵展
2023-03-14

如果您想更手动地执行此操作,您可以:

@GetMapping("/resources")
public Flux<Object> getResources() {
 return ReactiveSecurityContextHolder.getContext()
        .map(SecurityContext::getAuthentication)
        .map(Authentication::getPrincipal)
        .map(o -> (CurrentAccount) o)
        .filter(currentAccount -> 
            currentAccount.getUsername().equals("admin"))
        .switchIfEmpty(Mono.error(new ResponseStatusException(FORBIDDEN)))
        .then(<here further processing>);
}
牧熙云
2023-03-14

我找到了一个解决方案。

@PreAuthorize("@customSecurity.checkPermission(#account)")
@GetMapping("/")
public Object getWidgetValues(@AuthenticationPrincipal(expression = "account") Account account) {
    return "Hello admin";
}

其中,ReactiveUserDetailsService中使用的CurrentAccount

public class CurrentAccount extends User {
private Account account;

public CurrentAccount(Account account) {
    super(account.getLogin(), account.getPassword(), true, true,
            true, !account.isLocked(),
            AuthorityUtils.createAuthorityList(account.getRole().name()));
    this.account = account;
}
 类似资料:
  • 我有一个Restapi,它将从一个网站下载pdf文件,然后将pdf文件返回给调用者。 使用下面的代码,我可以得到

  • 在https://github.com/spring-projects/spring-framework/blob/master/spring-context/src/main/kotlin/org/springframework/context/support/BeanDefinitionDsl.kt该注释显示了如何通过新的“函数bean定义Kotlin DSL”定义SpringBean。我还发

  • 我正在使用SpringWebSockets,我想从存储库返回一个项目列表 我怎么能在WebSocket会话中发送此列表 这是如何将项目列表发送到websocket的处理程序方法

  • 请查看以下使用RestTemplate的controller代码(添加注释): 现在,我正试图通过反应式编程实现同样的目标。我现在使用WebFlux中的WebClient和Mono。但是,我很困惑如何将结果结合起来?看一看下面的代码(在任何地方都使用Mono,其余代码保持不变) 问题1:我们如何整合一切,形成一个Mono对象,并将其作为响应发送出去? 问题2:“CourseInfo CourseI

  • 我希望为每个请求生成唯一的traceId,并将其传递给所有服务。在SpringMVC中,使用MDC上下文并将traceId放在头文件中相当容易,但在反应式堆栈中,由于ThreadLocal,它根本不起作用。 一般来说,我希望使用单个traceId记录我拥有的每个服务上的每个请求和响应,该traceId可以识别整个系统中的特定操作。 我试图根据文章创建自定义过滤器:https://azizulhaq

  • 我正在使用reactive mongodb开发简单的spring webflux演示应用程序,我想按姓名读取员工的所有数据,但不包括姓名字段“joe”、“Sara”、“joe”、“Sara”,我有如下代码: //仓库接口 //服务类

  • 问题内容: 我正在使用spring-webflux WebClient (内部版本20170502.221452-172)访问Web应用程序,该Web应用程序生成Entry对象流(application / stream + json),如下所示: 尽管Entry对象的反序列化对于使用标准通用类型(包括Java时间(JSR-310)数据类型,如java.time.Instant)的POJO都可以正

  • 我正在使用spring-webflux WebClient(build 20170502.221452-172)访问一个Web应用程序,该应用程序生成一个条目对象流(application/stream+JSON),如下所示: 虽然条目对象的反序列化对于使用标准通用类型(包括Java.time.instant等Java time(JSR-310)数据类型)的POJO很好,但我想知道,为了将任何自定