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,69 @@
==============================================================================
Demo 4 -- what you can actually write inside @PreAuthorize / @PostAuthorize
==============================================================================
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.
alice: ROLE_USER, ROLE_AUDITOR, plus the authority 'report:read'
----------------------------------------------------------------
permitAll ALLOWED -> ok
denyAll DENIED -> AuthorizationDeniedException: Access Denied
isAuthenticated() ALLOWED -> ok
isAnonymous() DENIED -> AuthorizationDeniedException: Access Denied
isFullyAuthenticated() ALLOWED -> ok
isRememberMe() DENIED -> AuthorizationDeniedException: Access Denied
hasRole('ADMIN') DENIED -> AuthorizationDeniedException: Access Denied
hasAnyRole('ADMIN','AUDITOR') ALLOWED -> ok
hasAllRoles('USER','AUDITOR') ALLOWED -> ok
hasAuthority('report:read') ALLOWED -> ok
hasAnyAuthority('report:read','x') ALLOWED -> ok
hasAllAuthorities('report:read','x') DENIED -> AuthorizationDeniedException: Access Denied
authentication.name == 'alice' ALLOWED -> ok
principal == 'alice' ALLOWED -> ok
root: ROLE_ADMIN only (RoleHierarchy says ADMIN > USER > GUEST)
---------------------------------------------------------------
permitAll ALLOWED -> ok
denyAll DENIED -> AuthorizationDeniedException: Access Denied
isAuthenticated() ALLOWED -> ok
isAnonymous() DENIED -> AuthorizationDeniedException: Access Denied
isFullyAuthenticated() ALLOWED -> ok
isRememberMe() DENIED -> AuthorizationDeniedException: Access Denied
hasRole('ADMIN') ALLOWED -> ok
hasAnyRole('ADMIN','AUDITOR') ALLOWED -> ok
hasAllRoles('USER','AUDITOR') DENIED -> AuthorizationDeniedException: Access Denied
hasAuthority('report:read') DENIED -> AuthorizationDeniedException: Access Denied
hasAnyAuthority('report:read','x') DENIED -> AuthorizationDeniedException: Access Denied
hasAllAuthorities('report:read','x') DENIED -> AuthorizationDeniedException: Access Denied
authentication.name == 'alice' DENIED -> AuthorizationDeniedException: Access Denied
principal == 'alice' DENIED -> AuthorizationDeniedException: Access Denied
Role prefix and hierarchy
-------------------------
hasRole('USER') -> ROLE_USER ALLOWED -> ok
hasAuthority('USER') -> literal 'USER' DENIED -> AuthorizationDeniedException: Access Denied
hasAuthority('ROLE_USER') ALLOWED -> ok
root hasRole('GUEST') via RoleHierarchy ALLOWED -> ok
Method arguments, the return value, and bean references
-------------------------------------------------------
#owner == authentication.name ("alice") ALLOWED -> ok
#owner == authentication.name ("bob") DENIED -> AuthorizationDeniedException: Access Denied
@P("o") alias, #o == ...name ("alice") ALLOWED -> ok
#root.this (the target object) ALLOWED -> ok
#root.args[0] -- no such property DENIED -> IllegalArgumentException: Failed to evaluate expression '#root.args[0] == authentication.name' [cause: SpelEvaluationException: EL1008E: Property or field 'args' cannot be found on object of type 'org.springframework.security.access.expression.method.MethodSecurityExpressionRoot' - maybe not public or not valid?]
@policy.canRead(authentication, #id) id=1 ALLOWED -> ok
@policy.canRead(authentication, #id) id=9 DENIED -> AuthorizationDeniedException: Access Denied
hasPermission(#id, 'account', 'read') id=1 ALLOWED -> ok
hasPermission(#id, 'account', 'read') id=9 DENIED -> AuthorizationDeniedException: Access Denied
T(java.time.LocalDate) type reference ALLOWED -> ok
@PostAuthorize returnObject.owner == ...name ALLOWED -> Account[1,alice,100]
@PostAuthorize returnObject.owner == ...name DENIED -> AuthorizationDeniedException: Access Denied
The literal constants on SecurityExpressionRoot
-----------------------------------------------
permitAll / denyAll exist as BOTH a boolean field and a no-arg method,
and read/write/create/delete/admin are String constants meant for
hasPermission(..) -- e.g. hasPermission(#id, 'account', read).
hasPermission(#id, 'account', read) id=1 ALLOWED -> ok