mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-07-10 12:23:30 +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:
|
||||
|
||||
[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)`.
|
||||
|
||||
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
|
||||
|
@ -18,6 +18,9 @@ package org.springframework.security.web.access.expression;
|
||||
|
||||
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.Expression;
|
||||
import org.springframework.security.access.expression.ExpressionUtils;
|
||||
@ -51,11 +54,20 @@ public final class WebExpressionAuthorizationManager implements AuthorizationMan
|
||||
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
|
||||
* {@link DefaultHttpSecurityExpressionHandler}.
|
||||
* @param expressionHandler the {@link SecurityExpressionHandler} to use
|
||||
* @deprecated Please use {@link #withDefaults()} or {@link #withExpressionHandler}
|
||||
*/
|
||||
@Deprecated
|
||||
public void setExpressionHandler(SecurityExpressionHandler<RequestAuthorizationContext> expressionHandler) {
|
||||
Assert.notNull(expressionHandler, "expressionHandler cannot be null");
|
||||
this.expressionHandler = expressionHandler;
|
||||
@ -82,4 +94,78 @@ public final class WebExpressionAuthorizationManager implements AuthorizationMan
|
||||
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.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.ExpressionParser;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
@ -102,4 +103,49 @@ class WebExpressionAuthorizationManagerTests {
|
||||
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