1
0

Split into per-article modules and add the method-security module

Moves the existing virtual-thread/context-propagation project into
context-propagation/ and adds method-security/ for the Spring Security 7
method-security article: nine runnable demos, fourteen assertions, and every
transcript the article quotes, regenerated by scripts/run-all.sh.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RSrsDSRKVsY588yFiMJMo9
This commit is contained in:
2026-08-25 02:01:29 +00:00
parent 9f950bffa9
commit 5e9e7f1b12
65 changed files with 4088 additions and 119 deletions

View File

@@ -0,0 +1,58 @@
==============================================================================
Demo 6 -- interceptor order, and @PostAuthorize vs @Transactional
==============================================================================
AuthorizationInterceptorsOrder, read from the enum itself
---------------------------------------------------------
CONSTANT getOrder()
FIRST -2147483648
PRE_FILTER 100
PRE_AUTHORIZE 200
SECURED 300
JSR250 400
SECURE_RESULT 450
POST_AUTHORIZE 500
POST_FILTER 600
LAST 2147483647
Lower order = higher precedence = further OUT in the chain. Spring's own
@Transactional advisor defaults to Ordered.LOWEST_PRECEDENCE (2147483647),
which is larger than every number above -- so security wraps transactions,
not the other way round.
SLF4J(W): No SLF4J providers were found.
SLF4J(W): Defaulting to no-operation (NOP) logger implementation
SLF4J(W): See https://www.slf4j.org/codes.html#noProviders for further details.
The advisor chain on a bean carrying all four annotations
---------------------------------------------------------
advisors applied to the proxy: 4
ORDER ADVISOR BEAN (as registered by @EnableMethodSecurity)
100 preFilterAuthorizationMethodInterceptor
200 preAuthorizeAuthorizationMethodInterceptor
450 authorizeReturnObjectMethodInterceptor
500 postAuthorizeAuthorizationMethodInterceptor
600 postFilterAuthorizationMethodInterceptor
(authorizeReturnObject sits at SECURE_RESULT = 450 and is registered
whether or not anything in the app uses @AuthorizeReturnObject.)
For BEFORE advice, a lower order runs earlier: @PreFilter (100) really
does run before @PreAuthorize (200). For AFTER advice the same numbers
mean the opposite. @PostAuthorize (500) sits FURTHER OUT than
@PostFilter (600), so on the way back out @PostFilter finishes first
and @PostAuthorize evaluates returnObject on the ALREADY-FILTERED list.
Both methods below return the same 3 elements and filter one away:
@PostAuthorize returnObject.size() == 3 DENIED -> AuthorizationDeniedException: Access Denied
@PostAuthorize returnObject.size() == 2 ALLOWED -> [a, b]
Default order: @PostAuthorize denies AFTER the transaction commits
------------------------------------------------------------------
rows before : 0
recordAndReturn("bob") @PostAuthorize DENIED -> AuthorizationDeniedException: Access Denied
rows after the denial : 1
@EnableTransactionManagement(order = FIRST): the write rolls back
-----------------------------------------------------------------
rows before : 0
recordAndReturn("bob") @PostAuthorize DENIED -> AuthorizationDeniedException: Access Denied
rows after the denial : 0