Merge branch '5.7.x' into 5.8.x
Closes gh-13405
This commit is contained in:
@@ -29,8 +29,10 @@ For earlier versions, please read about similar support with <<jc-enable-global-
|
||||
For example, the following would enable Spring Security's `@PreAuthorize` annotation:
|
||||
|
||||
.Method Security Configuration
|
||||
====
|
||||
.Java
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@EnableMethodSecurity
|
||||
@@ -39,7 +41,8 @@ public class MethodSecurityConfig {
|
||||
}
|
||||
----
|
||||
|
||||
.Kotlin
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
@EnableMethodSecurity
|
||||
@@ -48,20 +51,23 @@ class MethodSecurityConfig {
|
||||
}
|
||||
----
|
||||
|
||||
.Xml
|
||||
Xml::
|
||||
+
|
||||
[source,xml,role="secondary"]
|
||||
----
|
||||
<sec:method-security/>
|
||||
----
|
||||
====
|
||||
======
|
||||
|
||||
Adding an annotation to a method (on a class or interface) would then limit the access to that method accordingly.
|
||||
Spring Security's native annotation support defines a set of attributes for the method.
|
||||
These will be passed to the `DefaultAuthorizationMethodInterceptorChain` for it to make the actual decision:
|
||||
|
||||
.Method Security Annotation Usage
|
||||
====
|
||||
.Java
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
public interface BankService {
|
||||
@@ -76,7 +82,8 @@ public interface BankService {
|
||||
}
|
||||
----
|
||||
|
||||
.Kotlin
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
interface BankService {
|
||||
@@ -90,13 +97,15 @@ interface BankService {
|
||||
fun post(account : Account, amount : Double) : Account
|
||||
}
|
||||
----
|
||||
====
|
||||
======
|
||||
|
||||
You can enable support for Spring Security's `@Secured` annotation using:
|
||||
|
||||
.@Secured Configuration
|
||||
====
|
||||
.Java
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@EnableMethodSecurity(securedEnabled = true)
|
||||
@@ -105,7 +114,8 @@ public class MethodSecurityConfig {
|
||||
}
|
||||
----
|
||||
|
||||
.Kotlin
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
@EnableMethodSecurity(securedEnabled = true)
|
||||
@@ -114,18 +124,21 @@ class MethodSecurityConfig {
|
||||
}
|
||||
----
|
||||
|
||||
.Xml
|
||||
Xml::
|
||||
+
|
||||
[source,xml,role="secondary"]
|
||||
----
|
||||
<sec:method-security secured-enabled="true"/>
|
||||
----
|
||||
====
|
||||
======
|
||||
|
||||
or JSR-250 using:
|
||||
|
||||
.JSR-250 Configuration
|
||||
====
|
||||
.Java
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@EnableMethodSecurity(jsr250Enabled = true)
|
||||
@@ -134,7 +147,8 @@ public class MethodSecurityConfig {
|
||||
}
|
||||
----
|
||||
|
||||
.Kotlin
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
@EnableMethodSecurity(jsr250Enabled = true)
|
||||
@@ -143,12 +157,13 @@ class MethodSecurityConfig {
|
||||
}
|
||||
----
|
||||
|
||||
.Xml
|
||||
Xml::
|
||||
+
|
||||
[source,xml,role="secondary"]
|
||||
----
|
||||
<sec:method-security jsr250-enabled="true"/>
|
||||
----
|
||||
====
|
||||
======
|
||||
|
||||
=== Customizing Authorization
|
||||
|
||||
@@ -158,8 +173,10 @@ Spring Security's `@PreAuthorize`, `@PostAuthorize`, `@PreFilter`, and `@PostFil
|
||||
If you need to customize the way that expressions are handled, you can expose a custom `MethodSecurityExpressionHandler`, like so:
|
||||
|
||||
.Custom MethodSecurityExpressionHandler
|
||||
====
|
||||
.Java
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@Bean
|
||||
@@ -170,7 +187,8 @@ static MethodSecurityExpressionHandler methodSecurityExpressionHandler() {
|
||||
}
|
||||
----
|
||||
|
||||
.Kotlin
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
companion object {
|
||||
@@ -183,7 +201,8 @@ companion object {
|
||||
}
|
||||
----
|
||||
|
||||
.Xml
|
||||
Xml::
|
||||
+
|
||||
[source,xml,role="secondary"]
|
||||
----
|
||||
<sec:method-security>
|
||||
@@ -195,7 +214,7 @@ companion object {
|
||||
<property name="trustResolver" ref="myCustomTrustResolver"/>
|
||||
</bean>
|
||||
----
|
||||
====
|
||||
======
|
||||
|
||||
[TIP]
|
||||
====
|
||||
@@ -208,8 +227,10 @@ Also, for role-based authorization, Spring Security adds a default `ROLE_` prefi
|
||||
You can configure the authorization rules to use a different prefix by exposing a `GrantedAuthorityDefaults` bean, like so:
|
||||
|
||||
.Custom MethodSecurityExpressionHandler
|
||||
====
|
||||
.Java
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@Bean
|
||||
@@ -218,7 +239,8 @@ static GrantedAuthorityDefaults grantedAuthorityDefaults() {
|
||||
}
|
||||
----
|
||||
|
||||
.Kotlin
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
companion object {
|
||||
@@ -229,7 +251,8 @@ companion object {
|
||||
}
|
||||
----
|
||||
|
||||
.Xml
|
||||
Xml::
|
||||
+
|
||||
[source,xml,role="secondary"]
|
||||
----
|
||||
<sec:method-security/>
|
||||
@@ -238,7 +261,7 @@ companion object {
|
||||
<constructor-arg value="MYPREFIX_"/>
|
||||
</bean>
|
||||
----
|
||||
====
|
||||
======
|
||||
|
||||
[TIP]
|
||||
====
|
||||
@@ -261,8 +284,10 @@ If that authorization denies access, the value is not returned, and an `AccessDe
|
||||
To recreate what adding `@EnableMethodSecurity` does by default, you would publish the following configuration:
|
||||
|
||||
.Full Pre-post Method Security Configuration
|
||||
====
|
||||
.Java
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@EnableMethodSecurity(prePostEnabled = false)
|
||||
@@ -293,7 +318,8 @@ class MethodSecurityConfig {
|
||||
}
|
||||
----
|
||||
|
||||
.Kotlin
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
@EnableMethodSecurity(prePostEnabled = false)
|
||||
@@ -324,7 +350,8 @@ class MethodSecurityConfig {
|
||||
}
|
||||
----
|
||||
|
||||
.Xml
|
||||
Xml::
|
||||
+
|
||||
[source,xml,role="secondary"]
|
||||
----
|
||||
<sec:method-security pre-post-enabled="false"/>
|
||||
@@ -342,15 +369,17 @@ class MethodSecurityConfig {
|
||||
<bean id="postFilterAuthorizationMethodInterceptor"
|
||||
class="org.springframework.security.authorization.method.PostFilterAuthorizationMethodInterceptor"/>
|
||||
----
|
||||
====
|
||||
======
|
||||
|
||||
Notice that Spring Security's method security is built using Spring AOP.
|
||||
So, interceptors are invoked based on the order specified.
|
||||
This can be customized by calling `setOrder` on the interceptor instances like so:
|
||||
|
||||
.Publish Custom Advisor
|
||||
====
|
||||
.Java
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@Bean
|
||||
@@ -362,7 +391,8 @@ Advisor postFilterAuthorizationMethodInterceptor() {
|
||||
}
|
||||
----
|
||||
|
||||
.Kotlin
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
@Bean
|
||||
@@ -374,7 +404,8 @@ fun postFilterAuthorizationMethodInterceptor() : Advisor {
|
||||
}
|
||||
----
|
||||
|
||||
.Xml
|
||||
Xml::
|
||||
+
|
||||
[source,xml,role="secondary"]
|
||||
----
|
||||
<bean id="postFilterAuthorizationMethodInterceptor"
|
||||
@@ -383,14 +414,16 @@ fun postFilterAuthorizationMethodInterceptor() : Advisor {
|
||||
value="#{T(org.springframework.security.authorization.method.AuthorizationInterceptorsOrder).POST_AUTHORIZE.getOrder() -1}"/>
|
||||
</bean>
|
||||
----
|
||||
====
|
||||
======
|
||||
|
||||
You may want to only support `@PreAuthorize` in your application, in which case you can do the following:
|
||||
|
||||
|
||||
.Only @PreAuthorize Configuration
|
||||
====
|
||||
.Java
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@EnableMethodSecurity(prePostEnabled = false)
|
||||
@@ -403,7 +436,8 @@ class MethodSecurityConfig {
|
||||
}
|
||||
----
|
||||
|
||||
.Kotlin
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
@EnableMethodSecurity(prePostEnabled = false)
|
||||
@@ -416,7 +450,8 @@ class MethodSecurityConfig {
|
||||
}
|
||||
----
|
||||
|
||||
.Xml
|
||||
Xml::
|
||||
+
|
||||
[source,xml,role="secondary"]
|
||||
----
|
||||
<sec:method-security pre-post-enabled="false"/>
|
||||
@@ -427,7 +462,7 @@ class MethodSecurityConfig {
|
||||
class="org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor"
|
||||
factory-method="preAuthorize"/>
|
||||
----
|
||||
====
|
||||
======
|
||||
|
||||
Or, you may have a custom before-method `AuthorizationManager` that you want to add to the list.
|
||||
|
||||
@@ -436,9 +471,11 @@ In this case, you will need to tell Spring Security both the `AuthorizationManag
|
||||
Thus, you can configure Spring Security to invoke your `AuthorizationManager` in between `@PreAuthorize` and `@PostAuthorize` like so:
|
||||
|
||||
.Custom Before Advisor
|
||||
====
|
||||
|
||||
.Java
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@EnableMethodSecurity
|
||||
@@ -456,7 +493,8 @@ class MethodSecurityConfig {
|
||||
}
|
||||
----
|
||||
|
||||
.Kotlin
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
@EnableMethodSecurity
|
||||
@@ -474,7 +512,8 @@ class MethodSecurityConfig {
|
||||
}
|
||||
----
|
||||
|
||||
.Xml
|
||||
Xml::
|
||||
+
|
||||
[source,xml,role="secondary"]
|
||||
----
|
||||
<sec:method-security/>
|
||||
@@ -496,7 +535,7 @@ class MethodSecurityConfig {
|
||||
value="#{T(org.springframework.security.authorization.method.AuthorizationInterceptorsOrder).PRE_AUTHORIZE_ADVISOR_ORDER.getOrder() + 1}"/>
|
||||
</bean>
|
||||
----
|
||||
====
|
||||
======
|
||||
|
||||
[TIP]
|
||||
====
|
||||
@@ -509,8 +548,10 @@ After-method authorization is generally concerned with analysing the return valu
|
||||
For example, you might have a method that confirms that the account requested actually belongs to the logged-in user like so:
|
||||
|
||||
.@PostAuthorize example
|
||||
====
|
||||
.Java
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
public interface BankService {
|
||||
@@ -521,7 +562,8 @@ public interface BankService {
|
||||
}
|
||||
----
|
||||
|
||||
.Kotlin
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
interface BankService {
|
||||
@@ -531,7 +573,7 @@ interface BankService {
|
||||
fun readAccount(id : Long) : Account
|
||||
}
|
||||
----
|
||||
====
|
||||
======
|
||||
|
||||
You can supply your own `AuthorizationMethodInterceptor` to customize how access to the return value is evaluated.
|
||||
|
||||
@@ -539,8 +581,10 @@ For example, if you have your own custom annotation, you can configure it like s
|
||||
|
||||
|
||||
.Custom After Advisor
|
||||
====
|
||||
.Java
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@EnableMethodSecurity
|
||||
@@ -556,7 +600,8 @@ class MethodSecurityConfig {
|
||||
}
|
||||
----
|
||||
|
||||
.Kotlin
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
@EnableMethodSecurity
|
||||
@@ -572,7 +617,8 @@ class MethodSecurityConfig {
|
||||
}
|
||||
----
|
||||
|
||||
.Xml
|
||||
Xml::
|
||||
+
|
||||
[source,xml,role="secondary"]
|
||||
----
|
||||
<sec:method-security/>
|
||||
@@ -594,7 +640,7 @@ class MethodSecurityConfig {
|
||||
value="#{T(org.springframework.security.authorization.method.AuthorizationInterceptorsOrder).PRE_AUTHORIZE_ADVISOR_ORDER.getOrder() + 1}"/>
|
||||
</bean>
|
||||
----
|
||||
====
|
||||
======
|
||||
|
||||
and it will be invoked after the `@PostAuthorize` interceptor.
|
||||
|
||||
@@ -604,8 +650,10 @@ and it will be invoked after the `@PostAuthorize` interceptor.
|
||||
We can enable annotation-based security using the `@EnableGlobalMethodSecurity` annotation on any `@Configuration` instance.
|
||||
For example, the following would enable Spring Security's `@Secured` annotation.
|
||||
|
||||
====
|
||||
.Java
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@EnableGlobalMethodSecurity(securedEnabled = true)
|
||||
@@ -614,7 +662,8 @@ public class MethodSecurityConfig {
|
||||
}
|
||||
----
|
||||
|
||||
.Kotlin
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
@EnableGlobalMethodSecurity(securedEnabled = true)
|
||||
@@ -622,14 +671,16 @@ open class MethodSecurityConfig {
|
||||
// ...
|
||||
}
|
||||
----
|
||||
====
|
||||
======
|
||||
|
||||
Adding an annotation to a method (on a class or interface) would then limit the access to that method accordingly.
|
||||
Spring Security's native annotation support defines a set of attributes for the method.
|
||||
These will be passed to the AccessDecisionManager for it to make the actual decision:
|
||||
|
||||
====
|
||||
.Java
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
public interface BankService {
|
||||
@@ -645,7 +696,8 @@ public Account post(Account account, double amount);
|
||||
}
|
||||
----
|
||||
|
||||
.Kotlin
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
interface BankService {
|
||||
@@ -659,12 +711,14 @@ interface BankService {
|
||||
fun post(account: Account, amount: Double): Account
|
||||
}
|
||||
----
|
||||
====
|
||||
======
|
||||
|
||||
Support for JSR-250 annotations can be enabled using
|
||||
|
||||
====
|
||||
.Java
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@EnableGlobalMethodSecurity(jsr250Enabled = true)
|
||||
@@ -673,7 +727,8 @@ public class MethodSecurityConfig {
|
||||
}
|
||||
----
|
||||
|
||||
.Kotlin
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
@EnableGlobalMethodSecurity(jsr250Enabled = true)
|
||||
@@ -681,13 +736,15 @@ open class MethodSecurityConfig {
|
||||
// ...
|
||||
}
|
||||
----
|
||||
====
|
||||
======
|
||||
|
||||
These are standards-based and allow simple role-based constraints to be applied but do not have the power Spring Security's native annotations.
|
||||
To use the new expression-based syntax, you would use
|
||||
|
||||
====
|
||||
.Java
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
@@ -696,7 +753,8 @@ public class MethodSecurityConfig {
|
||||
}
|
||||
----
|
||||
|
||||
.Kotlin
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
@@ -704,12 +762,14 @@ open class MethodSecurityConfig {
|
||||
// ...
|
||||
}
|
||||
----
|
||||
====
|
||||
======
|
||||
|
||||
and the equivalent Java code would be
|
||||
|
||||
====
|
||||
.Java
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
public interface BankService {
|
||||
@@ -725,7 +785,8 @@ public Account post(Account account, double amount);
|
||||
}
|
||||
----
|
||||
|
||||
.Kotlin
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
interface BankService {
|
||||
@@ -739,7 +800,7 @@ interface BankService {
|
||||
fun post(account: Account, amount: Double): Account
|
||||
}
|
||||
----
|
||||
====
|
||||
======
|
||||
|
||||
== GlobalMethodSecurityConfiguration
|
||||
|
||||
@@ -747,8 +808,10 @@ Sometimes you may need to perform operations that are more complicated than are
|
||||
For these instances, you can extend the `GlobalMethodSecurityConfiguration` ensuring that the `@EnableGlobalMethodSecurity` annotation is present on your subclass.
|
||||
For example, if you wanted to provide a custom `MethodSecurityExpressionHandler`, you could use the following configuration:
|
||||
|
||||
====
|
||||
.Java
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
@@ -761,7 +824,8 @@ public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
|
||||
}
|
||||
----
|
||||
|
||||
.Kotlin
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
@@ -772,7 +836,7 @@ open class MethodSecurityConfig : GlobalMethodSecurityConfiguration() {
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
======
|
||||
|
||||
For additional information about methods that can be overridden, refer to the `GlobalMethodSecurityConfiguration` Javadoc.
|
||||
|
||||
@@ -791,8 +855,10 @@ Adding an annotation to a method (on an class or interface) would then limit the
|
||||
Spring Security's native annotation support defines a set of attributes for the method.
|
||||
These will be passed to the `AccessDecisionManager` for it to make the actual decision:
|
||||
|
||||
====
|
||||
.Java
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
public interface BankService {
|
||||
@@ -809,7 +875,8 @@ public Account post(Account account, double amount);
|
||||
----
|
||||
|
||||
|
||||
.Kotlin
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
interface BankService {
|
||||
@@ -823,7 +890,7 @@ interface BankService {
|
||||
fun post(account: Account, amount: Double): Account
|
||||
}
|
||||
----
|
||||
====
|
||||
======
|
||||
|
||||
Support for JSR-250 annotations can be enabled using
|
||||
|
||||
@@ -842,8 +909,10 @@ To use the new expression-based syntax, you would use
|
||||
|
||||
and the equivalent Java code would be
|
||||
|
||||
====
|
||||
.Java
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
public interface BankService {
|
||||
@@ -859,7 +928,8 @@ public Account post(Account account, double amount);
|
||||
}
|
||||
----
|
||||
|
||||
.Kotlin
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
interface BankService {
|
||||
@@ -873,7 +943,7 @@ interface BankService {
|
||||
fun post(account: Account, amount: Double): Account
|
||||
}
|
||||
----
|
||||
====
|
||||
======
|
||||
|
||||
Expression-based annotations are a good choice if you need to define simple rules that go beyond checking the role names against the user's list of authorities.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user