Skip to content

Commit 8b9fe13

Browse files
committed
Document Messaging SpEL Migration
Issue gh-12650
1 parent 16272f6 commit 8b9fe13

File tree

1 file changed

+72
-0
lines changed

1 file changed

+72
-0
lines changed

docs/modules/ROOT/pages/servlet/integrations/websocket.adoc

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,78 @@ This will ensure that:
208208
<5> Any other message of type MESSAGE or SUBSCRIBE is rejected. Due to 6 we do not need this step, but it illustrates how one can match on specific message types.
209209
<6> Any other Message is rejected. This is a good idea to ensure that you do not miss any messages.
210210

211+
[[migrating-spel-expressions]]
212+
=== Migrating SpEL Expressions
213+
214+
If you are migrating from an older version of Spring Security, your destination matchers may include SpEL expressions.
215+
It's recommended that these be changed to using concrete implementations of `AuthorizationManager` since this is independently testable.
216+
217+
However, to ease migration, you can also use a class like the following:
218+
219+
[source,java]
220+
----
221+
public final class MessageExpressionAuthorizationManager implements AuthorizationManager<MessageAuthorizationContext<?>> {
222+
223+
private SecurityExpressionHandler<Message<?>> expressionHandler = new DefaultMessageSecurityExpressionHandler();
224+
225+
private Expression expression;
226+
227+
public MessageExpressionAuthorizationManager(String expressionString) {
228+
Assert.hasText(expressionString, "expressionString cannot be empty");
229+
this.expression = this.expressionHandler.getExpressionParser().parseExpression(expressionString);
230+
}
231+
232+
@Override
233+
public AuthorizationDecision check(Supplier<Authentication> authentication, MessageAuthorizationContext<?> context) {
234+
EvaluationContext ctx = this.expressionHandler.createEvaluationContext(authentication, context.getMessage());
235+
boolean granted = ExpressionUtils.evaluateAsBoolean(this.expression, ctx);
236+
return new ExpressionAuthorizationDecision(granted, this.expression);
237+
}
238+
239+
}
240+
----
241+
242+
And specify an instance for each matcher that you cannot get migrate:
243+
244+
[tabs]
245+
======
246+
Java::
247+
+
248+
[source,java,role="primary"]
249+
----
250+
@Configuration
251+
public class WebSocketSecurityConfig {
252+
253+
@Bean
254+
public AuthorizationManager<Message<?>> messageAuthorizationManager(MessageMatcherDelegatingAuthorizationManager.Builder messages) {
255+
messages
256+
// ...
257+
.simpSubscribeDestMatchers("/topic/friends/{friend}").access(new MessageExpressionAuthorizationManager("#friends == 'john"));
258+
// ...
259+
260+
return messages.build();
261+
}
262+
}
263+
----
264+
265+
Kotlin::
266+
+
267+
[source,kotlin,role="secondary"]
268+
----
269+
@Configuration
270+
open class WebSocketSecurityConfig {
271+
fun messageAuthorizationManager(messages: MessageMatcherDelegatingAuthorizationManager.Builder): AuthorizationManager<Message<?> {
272+
messages
273+
// ..
274+
.simpSubscribeDestMatchers("/topic/friends/{friends}").access(MessageExpressionAuthorizationManager("#friends == 'john"))
275+
// ...
276+
277+
return messages.build()
278+
}
279+
}
280+
----
281+
======
282+
211283
[[websocket-authorization-notes]]
212284
=== WebSocket Authorization Notes
213285

0 commit comments

Comments
 (0)