Merge 5c684a06a2
into 890049c6f7
This commit is contained in:
commit
91e4915b05
|
@ -57,12 +57,17 @@ import org.springframework.util.PropertyPlaceholderHelper;
|
|||
* {@code @HasRole} annotation found on a given {@link AnnotatedElement}.
|
||||
*
|
||||
* <p>
|
||||
* Meta-annotations that use enum values can use {@link ExpressionTemplateValueProvider} to
|
||||
* provide custom placeholder values.
|
||||
*
|
||||
* <p>
|
||||
* Since the process of synthesis is expensive, it is recommended to cache the synthesized
|
||||
* result to prevent multiple computations.
|
||||
*
|
||||
* @param <A> the annotation to search for and synthesize
|
||||
* @author Josh Cummings
|
||||
* @author DingHao
|
||||
* @author Mike Heath
|
||||
* @since 6.4
|
||||
*/
|
||||
final class ExpressionTemplateSecurityAnnotationScanner<A extends Annotation>
|
||||
|
@ -72,6 +77,7 @@ final class ExpressionTemplateSecurityAnnotationScanner<A extends Annotation>
|
|||
|
||||
static {
|
||||
conversionService.addConverter(new ClassToStringConverter());
|
||||
conversionService.addConverter(new ExpressionTemplateValueProviderConverter());
|
||||
}
|
||||
|
||||
private final Class<A> type;
|
||||
|
@ -160,4 +166,18 @@ final class ExpressionTemplateSecurityAnnotationScanner<A extends Annotation>
|
|||
|
||||
}
|
||||
|
||||
static class ExpressionTemplateValueProviderConverter implements GenericConverter {
|
||||
|
||||
@Override
|
||||
public Set<ConvertiblePair> getConvertibleTypes() {
|
||||
return Collections.singleton(new ConvertiblePair(ExpressionTemplateValueProvider.class, String.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
return (source != null) ? ((ExpressionTemplateValueProvider)source).getExpressionTemplateValue() : null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
package org.springframework.security.core.annotation;
|
||||
|
||||
/**
|
||||
* Provides a mechanism for providing custom values from enum types used in security
|
||||
* meta-annotation expressions. For example:
|
||||
*
|
||||
* <pre>
|
||||
* enum Permission implements ExpressionTemplateValueProvider {
|
||||
* READ,
|
||||
* WRITE;
|
||||
*
|
||||
* @Override
|
||||
* public String getExpressionTemplateValue() {
|
||||
* return switch (this) {
|
||||
* case READ -> "user.permission-read";
|
||||
* case WRITE -> "user.permission-write";
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @since 6.5
|
||||
* @author Mike Heath
|
||||
*/
|
||||
public interface ExpressionTemplateValueProvider {
|
||||
|
||||
/**
|
||||
* Returns the value to be used in an expression template.
|
||||
*
|
||||
* @return the value to be used in an expression template
|
||||
*/
|
||||
String getExpressionTemplateValue();
|
||||
|
||||
}
|
|
@ -54,6 +54,43 @@ public class ExpressionTemplateSecurityAnnotationScannerTests {
|
|||
assertThat(preAuthorize.value()).isEqualTo("check(#name)");
|
||||
}
|
||||
|
||||
@Test
|
||||
void parseMetaSourceAnnotationWithEnumImplementingExpressionTemplateValueProvider() throws Exception {
|
||||
Method method = MessageService.class.getDeclaredMethod("process");
|
||||
PreAuthorize preAuthorize = this.scanner.scan(method, method.getDeclaringClass());
|
||||
assertThat(preAuthorize.value()).isEqualTo("hasAnyAuthority(user.READ,user.WRITE)");
|
||||
}
|
||||
|
||||
enum Permission implements ExpressionTemplateValueProvider {
|
||||
READ,
|
||||
WRITE;
|
||||
|
||||
@Override
|
||||
public String getExpressionTemplateValue() {
|
||||
return switch (this) {
|
||||
case READ -> "user.READ";
|
||||
case WRITE -> "user.WRITE";
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.TYPE, ElementType.METHOD })
|
||||
@PreAuthorize("hasAnyAuthority({permissions})")
|
||||
@interface HasAnyCustomPermissions {
|
||||
|
||||
Permission[] permissions();
|
||||
|
||||
}
|
||||
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.TYPE, ElementType.METHOD })
|
||||
@HasAnyCustomPermissions(permissions = { Permission.READ, Permission.WRITE })
|
||||
@interface HasAllCustomPermissions {
|
||||
}
|
||||
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.TYPE, ElementType.METHOD })
|
||||
|
@ -86,6 +123,9 @@ public class ExpressionTemplateSecurityAnnotationScannerTests {
|
|||
|
||||
private interface MessageService {
|
||||
|
||||
@HasAllCustomPermissions
|
||||
void process();
|
||||
|
||||
@HasReadPermission("#name")
|
||||
String sayHello(String name);
|
||||
|
||||
|
|
Loading…
Reference in New Issue