mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-07-11 21:03:31 +00:00
Add WebExpressionAuthorizationManager.Builder
Closes gh-17504
This commit is contained in:
parent
c312d18191
commit
dadf10899c
@ -996,6 +996,29 @@ Kotlin::
|
|||||||
----
|
----
|
||||||
======
|
======
|
||||||
|
|
||||||
|
To migrate several, you can use `WebExpressionAuthorizationManager#withDefaults`:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
|
[source,java,role="primary"]
|
||||||
|
----
|
||||||
|
WebExpressionAuthorizationManager.Builder authz = WebExpressionAuthorizationManager.withDefaults();
|
||||||
|
.requestMatchers("/test/**").access(authz.expression("hasRole('ADMIN') && hasRole('USER')"))
|
||||||
|
.requestMatchers("/test/**").access(authz.expression("permitAll"))
|
||||||
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
|
[source,kotlin,role="secondary"]
|
||||||
|
----
|
||||||
|
var authz = WebExpressionAuthorizationManager.withDefaults()
|
||||||
|
.requestMatchers("/test/**").access(authz.expression("hasRole('ADMIN') && hasRole('USER')"))
|
||||||
|
.requestMatchers("/test/**").access(authz.expression("permitAll"))
|
||||||
|
----
|
||||||
|
======
|
||||||
|
|
||||||
If you are referring to a bean in your expression like so: `@webSecurity.check(authentication, request)`, it's recommended that you instead call the bean directly, which will look something like the following:
|
If you are referring to a bean in your expression like so: `@webSecurity.check(authentication, request)`, it's recommended that you instead call the bean directly, which will look something like the following:
|
||||||
|
|
||||||
[tabs]
|
[tabs]
|
||||||
@ -1019,7 +1042,32 @@ Kotlin::
|
|||||||
|
|
||||||
For complex instructions that include bean references as well as other expressions, it is recommended that you change those to implement `AuthorizationManager` and refer to them by calling `.access(AuthorizationManager)`.
|
For complex instructions that include bean references as well as other expressions, it is recommended that you change those to implement `AuthorizationManager` and refer to them by calling `.access(AuthorizationManager)`.
|
||||||
|
|
||||||
If you are not able to do that, you can configure a javadoc:org.springframework.security.web.access.expression.DefaultHttpSecurityExpressionHandler[] with a bean resolver and supply that to `WebExpressionAuthorizationManager#setExpressionhandler`.
|
If you are not able to do that, you can publish javadoc:org.springframework.security.web.access.expression.WebExpressionAuthorizationManager$Builder[] as a bean:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
|
[source,java,role="primary"]
|
||||||
|
----
|
||||||
|
@Bean
|
||||||
|
WebExpressionAuthorizationManager.Builder authz() {
|
||||||
|
return WebExpressionAuthorizationManager.withDefaults();
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
|
[source,kotlin,role="secondary"]
|
||||||
|
----
|
||||||
|
@Bean
|
||||||
|
fun authz(): WebExpressionAuthorizationManager.Builder {
|
||||||
|
return WebExpressionAuthorizationManager.withDefaults()
|
||||||
|
}
|
||||||
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
Then, expressions passed to that builder will be able to refer to beans.
|
||||||
|
|
||||||
[[security-matchers]]
|
[[security-matchers]]
|
||||||
== Security Matchers
|
== Security Matchers
|
||||||
|
@ -18,6 +18,9 @@ package org.springframework.security.web.access.expression;
|
|||||||
|
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import org.springframework.beans.BeansException;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.context.ApplicationContextAware;
|
||||||
import org.springframework.expression.EvaluationContext;
|
import org.springframework.expression.EvaluationContext;
|
||||||
import org.springframework.expression.Expression;
|
import org.springframework.expression.Expression;
|
||||||
import org.springframework.security.access.expression.ExpressionUtils;
|
import org.springframework.security.access.expression.ExpressionUtils;
|
||||||
@ -51,11 +54,20 @@ public final class WebExpressionAuthorizationManager implements AuthorizationMan
|
|||||||
this.expression = this.expressionHandler.getExpressionParser().parseExpression(expressionString);
|
this.expression = this.expressionHandler.getExpressionParser().parseExpression(expressionString);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private WebExpressionAuthorizationManager(String expressionString,
|
||||||
|
SecurityExpressionHandler<RequestAuthorizationContext> expressionHandler) {
|
||||||
|
Assert.hasText(expressionString, "expressionString cannot be empty");
|
||||||
|
this.expressionHandler = expressionHandler;
|
||||||
|
this.expression = expressionHandler.getExpressionParser().parseExpression(expressionString);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the {@link SecurityExpressionHandler} to be used. The default is
|
* Sets the {@link SecurityExpressionHandler} to be used. The default is
|
||||||
* {@link DefaultHttpSecurityExpressionHandler}.
|
* {@link DefaultHttpSecurityExpressionHandler}.
|
||||||
* @param expressionHandler the {@link SecurityExpressionHandler} to use
|
* @param expressionHandler the {@link SecurityExpressionHandler} to use
|
||||||
|
* @deprecated Please use {@link #withDefaults()} or {@link #withExpressionHandler}
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public void setExpressionHandler(SecurityExpressionHandler<RequestAuthorizationContext> expressionHandler) {
|
public void setExpressionHandler(SecurityExpressionHandler<RequestAuthorizationContext> expressionHandler) {
|
||||||
Assert.notNull(expressionHandler, "expressionHandler cannot be null");
|
Assert.notNull(expressionHandler, "expressionHandler cannot be null");
|
||||||
this.expressionHandler = expressionHandler;
|
this.expressionHandler = expressionHandler;
|
||||||
@ -82,4 +94,78 @@ public final class WebExpressionAuthorizationManager implements AuthorizationMan
|
|||||||
return "WebExpressionAuthorizationManager[expression='" + this.expression + "']";
|
return "WebExpressionAuthorizationManager[expression='" + this.expression + "']";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use a {@link DefaultHttpSecurityExpressionHandler} to create
|
||||||
|
* {@link WebExpressionAuthorizationManager} instances.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Note that publishing the {@link Builder} as a bean will allow the default
|
||||||
|
* expression handler to be configured with a bean provider so that expressions can
|
||||||
|
* reference beans
|
||||||
|
* @return a {@link Builder} for constructing
|
||||||
|
* {@link WebExpressionAuthorizationManager} instances
|
||||||
|
* @since 7.0
|
||||||
|
*/
|
||||||
|
public static Builder withDefaults() {
|
||||||
|
return new Builder();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this {@link SecurityExpressionHandler} to create
|
||||||
|
* {@link WebExpressionAuthorizationManager} instances
|
||||||
|
* @param expressionHandler
|
||||||
|
* @return a {@link Builder} for constructing
|
||||||
|
* {@link WebExpressionAuthorizationManager} instances
|
||||||
|
* @since 7.0
|
||||||
|
*/
|
||||||
|
public static Builder withExpressionHandler(
|
||||||
|
SecurityExpressionHandler<RequestAuthorizationContext> expressionHandler) {
|
||||||
|
return new Builder(expressionHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link Builder} for constructing {@link WebExpressionAuthorizationManager}
|
||||||
|
* instances.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* May be reused to create multiple instances.
|
||||||
|
*
|
||||||
|
* @author Josh Cummings
|
||||||
|
* @since 7.0
|
||||||
|
*/
|
||||||
|
public static final class Builder implements ApplicationContextAware {
|
||||||
|
|
||||||
|
private final SecurityExpressionHandler<RequestAuthorizationContext> expressionHandler;
|
||||||
|
|
||||||
|
private final boolean defaultExpressionHandler;
|
||||||
|
|
||||||
|
private Builder() {
|
||||||
|
this.expressionHandler = new DefaultHttpSecurityExpressionHandler();
|
||||||
|
this.defaultExpressionHandler = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Builder(SecurityExpressionHandler<RequestAuthorizationContext> expressionHandler) {
|
||||||
|
this.expressionHandler = expressionHandler;
|
||||||
|
this.defaultExpressionHandler = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a {@link WebExpressionAuthorizationManager} using this
|
||||||
|
* {@code expression}
|
||||||
|
* @param expression the expression to evaluate
|
||||||
|
* @return the resulting {@link AuthorizationManager}
|
||||||
|
*/
|
||||||
|
public WebExpressionAuthorizationManager expression(String expression) {
|
||||||
|
return new WebExpressionAuthorizationManager(expression, this.expressionHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setApplicationContext(ApplicationContext context) throws BeansException {
|
||||||
|
if (this.defaultExpressionHandler) {
|
||||||
|
((DefaultHttpSecurityExpressionHandler) this.expressionHandler).setApplicationContext(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ package org.springframework.security.web.access.expression;
|
|||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import org.springframework.context.support.GenericApplicationContext;
|
||||||
import org.springframework.expression.Expression;
|
import org.springframework.expression.Expression;
|
||||||
import org.springframework.expression.ExpressionParser;
|
import org.springframework.expression.ExpressionParser;
|
||||||
import org.springframework.mock.web.MockHttpServletRequest;
|
import org.springframework.mock.web.MockHttpServletRequest;
|
||||||
@ -102,4 +103,49 @@ class WebExpressionAuthorizationManagerTests {
|
|||||||
assertThat(decision.isGranted()).isFalse();
|
assertThat(decision.isGranted()).isFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void authorizeWhenDefaultsThenEvaluatesExpressionsReferencingBeans() {
|
||||||
|
GenericApplicationContext context = new GenericApplicationContext();
|
||||||
|
context.registerBean("bean", WebExpressionAuthorizationManagerTests.class, () -> this);
|
||||||
|
context.refresh();
|
||||||
|
WebExpressionAuthorizationManager.Builder builder = WebExpressionAuthorizationManager.withDefaults();
|
||||||
|
builder.setApplicationContext(context);
|
||||||
|
WebExpressionAuthorizationManager manager = builder
|
||||||
|
.expression("@bean.class.simpleName.startsWith('WebExpression')");
|
||||||
|
AuthorizationResult result = manager.authorize(TestAuthentication::authenticatedUser,
|
||||||
|
new RequestAuthorizationContext(new MockHttpServletRequest()));
|
||||||
|
assertThat(result.isGranted()).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void authorizeWhenDefaultsAsBeanThenEvaluatesExpressionsReferencingBeans() {
|
||||||
|
GenericApplicationContext context = new GenericApplicationContext();
|
||||||
|
context.registerBean("bean", WebExpressionAuthorizationManagerTests.class, () -> this);
|
||||||
|
context.registerBean("builder", WebExpressionAuthorizationManager.Builder.class,
|
||||||
|
WebExpressionAuthorizationManager::withDefaults);
|
||||||
|
context.refresh();
|
||||||
|
WebExpressionAuthorizationManager.Builder builder = context
|
||||||
|
.getBean(WebExpressionAuthorizationManager.Builder.class);
|
||||||
|
WebExpressionAuthorizationManager manager = builder
|
||||||
|
.expression("@bean.class.simpleName.startsWith('WebExpression')");
|
||||||
|
AuthorizationResult result = manager.authorize(TestAuthentication::authenticatedUser,
|
||||||
|
new RequestAuthorizationContext(new MockHttpServletRequest()));
|
||||||
|
assertThat(result.isGranted()).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void authorizeWhenExpressionHandlerHasBeanProviderThenEvaluatesExpressionsReferencingBeans() {
|
||||||
|
GenericApplicationContext context = new GenericApplicationContext();
|
||||||
|
context.registerBean("bean", WebExpressionAuthorizationManagerTests.class, () -> this);
|
||||||
|
context.refresh();
|
||||||
|
DefaultHttpSecurityExpressionHandler expressionHandler = new DefaultHttpSecurityExpressionHandler();
|
||||||
|
expressionHandler.setApplicationContext(context);
|
||||||
|
WebExpressionAuthorizationManager manager = WebExpressionAuthorizationManager
|
||||||
|
.withExpressionHandler(expressionHandler)
|
||||||
|
.expression("@bean.class.simpleName.startsWith('WebExpression')");
|
||||||
|
AuthorizationResult result = manager.authorize(TestAuthentication::authenticatedUser,
|
||||||
|
new RequestAuthorizationContext(new MockHttpServletRequest()));
|
||||||
|
assertThat(result.isGranted()).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user