| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
Reactive method-level authorization for Spring WebFlux. A single auto-configuration turns on Spring Security's reactive method interceptors (@PreAuthorize/@PostAuthorize) and registers the framework's @Secure interceptor as ergonomic, fail-closed sugar on top of them — no security code, and method calls deny by default unless the validated principal satisfies the requirement.
This module is the method-security binding of the Firefly hexagonal security platform. Where the resource-server module guards the edge (every inbound request must present a signature-validated bearer token before reaching a handler), this module guards individual service methods, so authorization can be expressed declaratively next to the business logic it protects.
It does two things. First, it switches on Spring Security 6's reactive method security — @EnableReactiveMethodSecurity — so the standard @PreAuthorize/@PostAuthorize annotations are enforced against the reactive security context. Second, it contributes a @Secure method interceptor that resolves the framework's @Secure annotation (declared in security-api) and evaluates it through the framework-neutral SecureAuthorizationEvaluator from security-core. @Secure is product-agnostic, fail-closed declarative authorization: a method (or its declaring class) denies unless the current SecurityPrincipal holds the declared roles, scopes, permissions, and/or satisfies an optional SpEL expression.
The whole module is one @AutoConfiguration class plus a single ReactiveAuthorizationManager. The interceptor bean is contributed unconditionally as infrastructure, but it composes cleanly with native Spring annotations — @Secure and @PreAuthorize can coexist on the same bean.
The security platform is layered hexagonally; dependencies point inward, and providers attach as outboard adapters:
security-api → security-spi → security-core → security-webflux → security-method-policy → adapters
(ports + (driven (neutral (reactive (this module: (Vault, KMS,
domain, ports) engine, Spring Security @EnableReactiveMethod- OPA, Keycloak,
@Secure) SecureAuth- bindings) Security + @Secure internal-db, …)
Evaluator) interceptor)
This module depends only on security-core and security-webflux (which transitively bring -spi and -api) plus spring-security-config and spring-boot-autoconfigure. It imports no vendor SDK.
MethodSecurityAutoConfiguration (annotated @AutoConfiguration @EnableReactiveMethodSecurity) contributes:
SecureMethodAuthorizationManager is a ReactiveAuthorizationManager<MethodInvocation> that:
It is fail-closed: an unauthenticated caller (empty/anonymous context) yields new AuthorizationDecision(false) via defaultIfEmpty, and a principal that does not satisfy the requirement is denied. A denial surfaces to the caller as Spring Security's AuthorizationDeniedException on the reactive stream.
| Type | Role |
|---|---|
| MethodSecurityAutoConfiguration | @AutoConfiguration @EnableReactiveMethodSecurity entry point; enables reactive method security and registers the @Secure interceptor. |
| SecureMethodAuthorizationManager | ReactiveAuthorizationManager<MethodInvocation> that resolves @Secure, builds a SecureRequirement, and evaluates it against the reactive SecurityPrincipal, fail-closed. |
Annotation enforced (from security-api): @Secure (roles, scopes, permissions, requireAllRoles/requireAllScopes/requireAllPermissions, expression). Engine consumed (from security-core): SecureRequirement, SecureAuthorizationEvaluator, Decision. Reactive glue consumed (from security-webflux): PrincipalSupport, FireflyAuthenticationToken. Domain (from security-api): SecurityPrincipal.
The auto-configuration is registered via META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports.
The version is managed by the Firefly parent/BOM, so you can usually omit it. In a Firefly application this module is pulled in transitively by the application starter; depend on it directly only when enabling method security standalone:
<dependency>
<groupId>org.fireflyframework</groupId>
<artifactId>fireflyframework-security-method-policy</artifactId>
</dependency>If you are not inheriting the Firefly parent, pin the version explicitly:
<dependency>
<groupId>org.fireflyframework</groupId>
<artifactId>fireflyframework-security-method-policy</artifactId>
<version>26.06.01</version>
</dependency>With the module on the classpath, reactive method security is active with zero code. Annotate the methods (or classes) you want to protect:
import org.fireflyframework.security.api.annotation.Secure;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;
@Service
class AccountService {
// Framework sugar: ANY of the listed roles suffices (fail-closed).
@Secure(roles = "admin")
Mono<Account> close(String accountId) {
return ...;
}
// Require a scope AND a fine-grained permission, both fully matched.
@Secure(scopes = "accounts.write", permissions = "account:close", requireAllPermissions = true)
Mono<Void> freeze(String accountId) {
return ...;
}
// Standard Spring annotation, enforced against the same reactive context.
@PreAuthorize("hasAuthority('teller')")
Mono<Balance> balance(String accountId) {
return ...;
}
}@Secure accepts roles, scopes, permissions, and an optional SpEL expression. Across those dimensions all declared dimensions must pass (AND); within a single dimension the requireAll* flag switches between ANY (default) and ALL matching. An empty @Secure simply requires an authenticated principal.
Mono<T> method() guarded by @Secure
→ fireflySecureMethodInterceptor (pointcut: @Secure on method or class)
→ SecureMethodAuthorizationManager.check(...)
→ resolve @Secure (method first, then target class)
→ SecureRequirement.from(secure)
→ PrincipalSupport.extract(Authentication) // from ReactiveSecurityContextHolder
→ SecureAuthorizationEvaluator.evaluate(principal, requirement) → Decision
→ AuthorizationDecision(granted)
→ granted ? proceed : AuthorizationDeniedException
A null/unauthenticated principal is denied; each declared dimension is checked in turn (roles, scopes, permissions, then expression), and a failing or throwing SpEL expression denies. Only a principal that satisfies every declared dimension reaches the method body.
The module ships a @SpringBootTest integration test, MethodSecurityIntegrationTest (webEnvironment = NONE), that boots a real Spring context with the real MethodSecurityAutoConfiguration and drives a SecuredService whose methods are annotated with @Secure and @PreAuthorize. It exercises both annotation styles end to end against the reactive security context — establishing identity with ReactiveSecurityContextHolder.withAuthentication(...) and a FireflyAuthenticationToken built over a SecurityPrincipal, then asserting outcomes with StepVerifier:
These mirror the platform's negative-path verification strategy: the unauthenticated and missing-authority deny paths are proven, not assumed.
Copyright 2024-2026 Firefly Software Foundation.
Licensed under the Apache License, Version 2.0. See LICENSE for details.
| Back | FazBrowse Home | New Git URL |