In addition to xref:servlet/authorization/authorize-http-requests.adoc[modeling authorization at the request level], Spring Security also supports modeling at the method level.
You can activate it in your application by annotating any `@Configuration` class with `@EnableMethodSecurity` or adding `<method-security>` to any XML configuration file, like so:
Then, you are immediately able to annotate any Spring-managed class or method with <<use-preauthorize, `@PreAuthorize`>>, <<use-postauthorize,`@PostAuthorize`>>, <<use-prefilter,`@PreFilter`>>, and <<use-postfilter,`@PostFilter`>> to authorize method invocations, including the input parameters and return values.
[NOTE]
{spring-boot-reference-url}using.html#using.build-systems.starters[Spring Boot Starter Security] does not activate method-level authorization by default.
Method Security supports many other use cases as well including <<use-aspectj, AspectJ support>>, <<use-programmatic-authorization,custom annotations>>, and several configuration points.
Consider learning about the following use cases:
* <<migration-enableglobalmethodsecurity, Migrating from `@EnableGlobalMethodSecurity`>>
* Understanding <<method-security-architecture,how method security works>> and reasons to use it
* Comparing <<request-vs-method,request-level and method-level authorization>>
* Authorizing methods with <<use-preauthorize,`@PreAuthorize`>> and <<use-postauthorize,`@PostAuthorize`>>
* Filtering methods with <<use-prefilter,`@PreFilter`>> and <<use-postfilter,`@PostFilter`>>
* Authorizing methods with <<use-jsr250,JSR-250 annotations>>
* Authorizing methods with <<use-aspectj,AspectJ expressions>>
* Integrating with <<weave-aspectj,AspectJ byte-code weaving>>
Spring Security's method authorization support is handy for:
* Extracting fine-grained authorization logic; for example, when the method parameters and return values contribute to the authorization decision.
* Enforcing security at the service layer
* Stylistically favoring annotation-based over `HttpSecurity`-based configuration
And since Method Security is built using {spring-framework-reference-url}core.html#aop-api[Spring AOP], you have access to all its expressive power to override Spring Security's defaults as needed.
As already mentioned, you begin by adding `@EnableMethodSecurity` to a `@Configuration` class or `<sec:method-security/>` in a Spring XML configuration file.
[[use-method-security]]
[NOTE]
====
This annotation and XML element supercede `@EnableGlobalMethodSecurity` and `<sec:global-method-security/>`, respectively.
A given invocation to `MyCustomerService#readCustomer` may look something like this when Method Security <<activate-method-security,is activated>>:
image::{figures}/methodsecurity.png[]
1. Spring AOP invokes its proxy method for `readCustomer`. Among the proxy's other advisors, it invokes an {security-api-url}org/springframework/security/authorization/method/AuthorizationManagerBeforeMethodInterceptor/html[`AuthorizationManagerBeforeMethodInterceptor`] that matches <<annotation-method-pointcuts,the `@PreAuthorize` pointcut>>
2. The interceptor invokes {security-api-url}org/springframework/security/authorization/method/PreAuthorizeAuthorizationManager.html[`PreAuthorizeAuthorizationManager#check`]
3. The authorization manager uses a `MethodSecurityExpressionHandler` to parse the annotation's xref:servlet/authorization/expression-based.adoc[SpEL expression] and constructs a corresponding `EvaluationContext` from a `MethodSecurityExpressionRoot` containing xref:servlet/authentication/architecture.adoc#servlet-authentication-authentication[a `Supplier<Authentication>`] and `MethodInvocation`.
4. The interceptor uses this context to evaluate the expression; specifically, it reads xref:servlet/authentication/architecture.adoc#servlet-authentication-authentication[the `Authentication`] from the `Supplier` and checks whether it has `permission:read` in its collection of xref:servlet/authorization/architecture.adoc#authz-authorities[authorities]
5. If the evaluation passes, then Spring AOP proceeds to invoke the method.
6. If not, the interceptor publishes an `AuthorizationDeniedEvent` and throws an {security-api-url}org/springframework/security/access/AccessDeniedException.html[`AccessDeniedException`] which xref:servlet/architecture.adoc#servlet-exceptiontranslationfilter[the `ExceptionTranslationFilter`] catches and returns a 403 status code to the response
7. After the method returns, Spring AOP invokes an {security-api-url}org/springframework/security/authorization/method/AuthorizationManagerAfterMethodInterceptor.html[`AuthorizationManagerAfterMethodInterceptor`] that matches <<annotation-method-pointcuts,the `@PostAuthorize` pointcut>>, operating the same as above, but with {security-api-url}org/springframework/security/authorization/method/PostAuthorizeAuthorizationManager.html[`PostAuthorizeAuthorizationManager`]
8. If the evaluation passes (in this case, the return value belongs to the logged-in user), processing continues normally
9. If not, the interceptor publishes an `AuthorizationDeniedEvent` and throws an {security-api-url}org/springframework/security/access/AccessDeniedException.html[`AccessDeniedException`], which xref:servlet/architecture.adoc#servlet-exceptiontranslationfilter[the `ExceptionTranslationFilter`] catches and returns a 403 status code to the response
[NOTE]
If the method is not being called in the context of an HTTP request, you will likely need to handle the `AccessDeniedException` yourself
[[unanimous-based-authorization-decisions]]
=== Multiple Annotations Are Computed In Series
As demonstrated above, if a method invocation involves multiple <<authorizing-with-annotations,Method Security annotations>>, each of those is processed one at a time.
This means that they can collectively be thought of as being "anded" together.
In other words, for an invocation to be authorized, all annotation inspections need to pass authorization.
[[repeated-annotations]]
=== Repeated Annotations Are Not Supported
That said, it is not supported to repeat the same annotation on the same method.
For example, you cannot please `@PreAuthorize` twice on the same method.
Instead, use SpEL's boolean support or its support for delegating to a separate bean.
[[annotation-method-pointcuts]]
=== Each Annotation Has Its Own Pointcut
Each annotation has its own pointcut instance that looks for that annotation or its <<meta-annotations,meta-annotation>> counterparts across the entire object hierarchy, starting at <<class-or-interface-annotations,the method and its enclosing class>>.
You can see the specifics of this in {security-api-url}org/springframework/security/authorization/method/AuthorizationMethodPointcuts.html[`AuthorizationMethodPointcuts`].
[[annotation-method-interceptors]]
=== Each Annotation Has Its Own Method Interceptor
Each annotation has its own dedicated method interceptor.
The reason for this is to make things more composable.
For example, if needed, you can disable the Spring Security defaults and <<_enabling_certain_annotations,publish only the `@PostAuthorize` method interceptor>>.
The method interceptors are as follows:
* For <<use-preauthorize,`@PreAuthorize`>>, Spring Security uses {security-api-url}org/springframework/security/authorization/method/AuthorizationManagerBeforeMethodInterceptor.html[`AuthenticationManagerBeforeMethodInterceptor#preAuthorize`], which in turn uses {security-api-url}org/springframework/security/authorization/method/PreAuthorizeAuthorizationManager.html[`PreAuthorizeAuthorizationManager`]
* For <<use-postauthorize,`@PostAuthorize`>>, Spring Security uses {security-api-url}org/springframework/security/authorization/method/AuthorizationManagerAfterMethodInterceptor.html[`AuthenticationManagerAfterMethodInterceptor#postAuthorize`], which in turn uses {security-api-url}org/springframework/security/authorization/method/PostAuthorizeAuthorizationManager.html[`PostAuthorizeAuthorizationManager`]
* For <<use-prefilter,`@PreFilter`>>, Spring Security uses {security-api-url}org/springframework/security/authorization/method/PreFilterAuthorizationMethodInterceptor.html[`PreFilterAuthorizationMethodInterceptor`]
* For <<use-postfilter,`@PostFilter`>>, Spring Security uses {security-api-url}org/springframework/security/authorization/method/PostFilterAuthorizationMethodInterceptor.html[`PostFilterAuthorizationMethodInterceptor`]
* For <<use-secured,`@Secured`>>, Spring Security uses {security-api-url}org/springframework/security/authorization/method/AuthorizationManagerBeforeMethodInterceptor.html[`AuthenticationManagerBeforeMethodInterceptor#secured`], which in turn uses {security-api-url}org/springframework/security/authorization/method/SecuredAuthorizationManager.html[`SecuredAuthorizationManager`]
* For JSR-250 annotations, Spring Security uses {security-api-url}org/springframework/security/authorization/method/AuthorizationManagerBeforeMethodInterceptor.html[`AuthenticationManagerBeforeMethodInterceptor#jsr250`], which in turn uses {security-api-url}org/springframework/security/authorization/method/Jsr250AuthorizationManager.html[`Jsr250AuthorizationManager`]
Generally speaking, you can consider the following listing as representative of what interceptors Spring Security publishes when you add `@EnableMethodSecurity`:
The main tradeoff seems to be where you want your authorization rules to live.
[NOTE]
It's important to remember that when you use annotation-based Method Security, then unannotated methods are not secured.
To protect against this, declare xref:servlet/authorization/authorize-http-requests.adoc#activate-request-security[a catch-all authorization rule] in your xref:servlet/configuration/java.adoc#jc-httpsecurity[`HttpSecurity`] instance.
[[authorizing-with-annotations]]
== Authorizing with Annotations
The primary way Spring Security enables method-level authorization support is through annotations that you can add to methods, classes, and interfaces.
[[use-preauthorize]]
=== Authorizing Method Invocation with `@PreAuthorize`
When <<activate-method-security,Method Security is active>>, you can annotate a method with the {security-api-url}org/springframework/security/access/prepost/PreAuthorize.html[`@PreAuthorize`] annotation like so:
====
.Java
[source,java,role="primary"]
----
@Component
public class BankService {
@PreAuthorize("hasRole('ADMIN')")
public Account readAccount(Long id) {
// ... is only invoked if the `Authentication` has the `ROLE_ADMIN` authority
`@PreAuthorize` also can be a <<meta-annotations, meta-annotation>>, be defined <<class-or-interface-annotations,at the class or interface level>>, and use xref:servlet/authorization/expression-based.adoc[SpEL authorization expressions].
While `@PreAuthorize` is quite helpful for declaring needed authorities, it can also be used to evaluate more complex permissions that involve the method parameters.
To achieve that, you can use Spring Security's `@P` annotation to remember the parameter name:
The above two snippets are ensuring that the user can only request orders that belong to them by comparing the username parameter to xref:servlet/authentication/architecture.adoc#servlet-authentication-authentication[`Authentication#getName`].
The result is that the above method will only be invoked if the `username` in the request path matches the logged-in user's `name`.
If not, Spring Security will throw an `AccessDeniedException` and return a 403 status code.
[[use-postauthorize]]
=== Authorization Method Results with `@PostAuthorize`
When Method Security is active, you can annotate a method with the {security-api-url}org/springframework/security/access/prepost/PostAuthorize.html[`@PostAuthorize`] annotation like so:
`@PostAuthorize` also can be a <<meta-annotations,meta-annotation>>, be defined <<class-or-interface-annotations,at the class or interface level>>, and use xref:servlet/authorization/expression-based.adoc[SpEL Authorization Expressions].
`@PostAuthorize` is particularly helpful when defending against https://cheatsheetseries.owasp.org/cheatsheets/Insecure_Direct_Object_Reference_Prevention_Cheat_Sheet.html[Insecure Direct Object Reference].
In fact, it can be defined as a <<meta-annotations,meta-annotation>> like so:
The result is that the above method will only return the `Account` if its `owner` attribute matches the logged-in user's `name`.
If not, Spring Security will throw an `AccessDeniedException` and return a 403 status code.
[[use-prefilter]]
=== Filtering Method Parameters with `@PreFilter`
[NOTE]
`@PreFilter` is not yet supported for Kotlin-specific data types; for that reason, only Java snippets are shown
When Method Security is active, you can annotate a method with the {security-api-url}org/springframework/security/access/prepost/PreFilter.html[`@PreFilter`] annotation like so:
`@PreFilter` also can be a <<meta-annotations,meta-annotation>>, be defined <<class-or-interface-annotations,at the class or interface level>>, and use xref:servlet/authorization/expression-based.adoc[SpEL Authorization Expressions].
`@PreFilter` supports arrays, collections, maps, and streams (so long as the stream is still open).
For example, the above `updateAccounts` declaration will function the same way as the following other four:
`@PostFilter` is not yet supported for Kotlin-specific data types; for that reason, only Java snippets are shown
When Method Security is active, you can annotate a method with the {security-api-url}org/springframework/security/access/prepost/PostFilter.html[`@PostFilter`] annotation like so:
`@PostFilter` also can be a <<meta-annotations,meta-annotation>>, be defined <<class-or-interface-annotations,at the class or interface level>>, and use xref:servlet/authorization/expression-based.adoc[SpEL Authorization Expressions].
public Stream<Account> readAccounts(String... ids)
```
The result is that the above method will return the `Account` instances where their `owner` attribute matches the logged-in user's `name`.
[NOTE]
In-memory filtering can obviously be expensive, and so be considerate of whether it is better to xref:servlet/integrations/data.adoc[filter the data in the data layer] instead.
[[use-secured]]
=== Authorizing Method Invocation with `@Secured`
{security-api-url}org/springframework/security/access/annotation/Secured.html[`@Secured`] is a legacy option for authorizing invocations.
<<use-preauthorize,`@PreAuthorize`>> supercedes it and is recommended instead.
To use the `@Secured` annotation, you should first change your Method Security declaration to enable it like so:
====
.Java
[source,java,role="primary"]
----
@EnableMethodSecurity(securedEnabled = true)
----
.Kotlin
[source,kotlin,role="secondary"]
----
@EnableMethodSecurity(securedEnabled = true)
----
.Xml
[source,xml,role="secondary"]
----
<sec:method-security secured-enabled="true"/>
----
====
This will cause Spring Security to publish <<annotation-method-interceptors,the corresponding method interceptor>> that authorizes methods, classes, and interfaces annotated with `@Secured`.
[[use-jsr250]]
=== Authorizing Method Invocation with JSR-250 Annotations
In case you would like to use https://jcp.org/en/jsr/detail?id=250[JSR-250] annotations, Spring Security also supports that.
<<use-preauthorize,`@PreAuthorize`>> has more expressive power and is thus recommended.
To use the JSR-250 annotations, you should first change your Method Security declaration to enable them like so:
====
.Java
[source,java,role="primary"]
----
@EnableMethodSecurity(jsr250Enabled = true)
----
.Kotlin
[source,kotlin,role="secondary"]
----
@EnableMethodSecurity(jsr250Enabled = true)
----
.Xml
[source,xml,role="secondary"]
----
<sec:method-security jsr250-enabled="true"/>
----
====
This will cause Spring Security to publish <<annotation-method-interceptors,the corresponding method interceptor>> that authorizes methods, classes, and interfaces annotated with `@RolesAllowed`, `@PermitAll`, and `@DenyAll`.
[[class-or-interface-annotations]]
=== Declaring Annotations at the Class or Interface Level
It's also supported to have Method Security annotations at the class and interface level.
The above snippet achieves this by first disabling Method Security's pre-configurations and then publishing <<annotation-method-interceptors, the `@PostAuthorize` interceptor>> itself.
While using Spring Security's <<authorizing-with-annotations,annotation-based support>> is preferred for method security, you can also use XML to declare bean authorization rules.
If you need to declare it in your XML configuration instead, you can use xref:servlet/appendix/namespace/method-security.adoc#nsa-intercept-methods[`<intercept-methods>`] like so:
This only supports matching method by prefix or by name.
If your needs are more complex than that, <<authorizing-with-annotations,use annotation support>> instead.
[[use-programmatic-authorization]]
== Authorizing Methods Programmatically
As you've already seen, there are several ways that you can specify non-trivial authorization rules using xref:servlet/authorization/expression-based.adoc[Method Security SpEL expressions].
There are a number of ways that you can instead allow your logic to be Java-based instead of SpEL-based.
This gives use access the entire Java language for increased testability and flow control.
=== Using a Custom Bean in SpEL
The first way to authorize a method programmatically is a two-step process.
First, declare a bean that has a method that takes a `MethodSecurityExpressionOperations` instance like the following:
The second way to authorize a method programmatically is two create a custom xref:servlet/authorization/architecture.adoc#_the_authorizationmanager[`AuthorizationManager`].
First, declare an authorization manager instance, perhaps like this one:
Or, third, you can customize how each SpEL expression is handled.
To do that, you can expose a custom {security-api-url}org.springframework.security.access.expression.method.MethodSecurityExpressionHandler.html[`MethodSecurityExpressionHandler`], like so:
We expose `MethodSecurityExpressionHandler` using a `static` method to ensure that Spring publishes it before it initializes Spring Security's method security `@Configuration` classes
You can also <<subclass-defaultmethodsecurityexpressionhandler,subclass `DefaultMessageSecurityExpressionHandler`>> to add your own custom authorization expressions beyond the defaults.
[[use-aspectj]]
== Authorizing with AspectJ
[[match-by-pointcut]]
=== Matching Methods with Custom Pointcuts
Being built on Spring AOP, you can declare patterns that are not related to annotations, similar to xref:servlet/authorization/authorize-http-requests.adoc[request-level authorization].
This has the potential advantage of centralizing method-level authorization rules.
For example, you can use publish your own `Advisor` or use xref:servlet/appendix/namespace/method-security.adoc#nsa-protect-pointcut[`<protect-pointcut>`] to match AOP expressions to authorization rules for your service layer like so:
Performance can at times be enhanced by using AspectJ to weave Spring Security advice into the byte code of your beans.
After setting up AspectJ, you can quite simply state in the `@EnableMethodSecurity` annotation or `<method-security>` element that you are using AspectJ:
=== Replace xref:servlet/authorization/method-security.adoc#jc-enable-global-method-security[global method security] with xref:servlet/authorization/method-security.adoc#jc-enable-method-security[method security]
{security-api-url}org/springframework/security/config/annotation/method/configuration/EnableGlobalMethodSecurity.html[`@EnableGlobalMethodSecurity`] and xref:servlet/appendix/namespace/method-security.adoc#nsa-global-method-security[`<global-method-security>`] are deprecated in favor of {security-api-url}org/springframework/security/config/annotation/method/configuration/EnableMethodSecurity.html[`@EnableMethodSecurity`] and xref:servlet/appendix/namespace/method-security.adoc#nsa-method-security[`<method-security>`], respectively.
The new annotation and XML element activate Spring's xref:servlet/authorization/method-security.adoc#jc-enable-method-security[pre-post annotations] by default and use `AuthorizationManager` internally.
This means that the following two listings are functionally equivalent:
As a performance optimization, a new method was introduced to `MethodSecurityExpressionHandler` that takes a `Supplier<Authentication>` instead of an `Authentication`.
This allows Spring Security to defer the lookup of the `Authentication`, and is taken advantage of automatically when you use `@EnableMethodSecurity` instead of `@EnableGlobalMethodSecurity`.
However, let's say that your code extends `DefaultMethodSecurityExpressionHandler` and overrides `createSecurityExpressionRoot(Authentication, MethodInvocation)` to return a custom `SecurityExpressionRoot` instance.
This will no longer work because the arrangement that `@EnableMethodSecurity` sets up calls `createEvaluationContext(Supplier<Authentication>, MethodInvocation)` instead.
Happily, such a level of customization is often unnecessary.
Instead, you can create a custom bean with the authorization methods that you need.
Now that you have secured your application's requests, please xref:servlet/authorization/authorize-http-requests.adoc[secure its requests] if you haven't already.
You can also read further on xref:servlet/test/index.adoc[testing your application] or on integrating Spring Security with other aspects of you application like xref:servlet/integrations/data.adoc[the data layer] or xref:servlet/integrations/observability.adoc[tracing and metrics].