Add @AuthenticationPrincipal expression
It is now possible to provide a SpEL expression for @AuthenticationPrincipal. This allows invoking custom logic including methods on the principal object. Fixes gh-3859
This commit is contained in:
+21
-2
@@ -19,12 +19,17 @@ import java.lang.annotation.Annotation;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.ExpressionParser;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Allows resolving the {@link Authentication#getPrincipal()} using the
|
||||
@@ -79,6 +84,8 @@ import org.springframework.stereotype.Controller;
|
||||
public final class AuthenticationPrincipalArgumentResolver
|
||||
implements HandlerMethodArgumentResolver {
|
||||
|
||||
private ExpressionParser parser = new SpelExpressionParser();
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
@@ -106,10 +113,22 @@ public final class AuthenticationPrincipalArgumentResolver
|
||||
return null;
|
||||
}
|
||||
Object principal = authentication.getPrincipal();
|
||||
|
||||
AuthenticationPrincipal authPrincipal = findMethodAnnotation(
|
||||
AuthenticationPrincipal.class, parameter);
|
||||
|
||||
String expressionToParse = authPrincipal.expression();
|
||||
if (StringUtils.hasLength(expressionToParse)) {
|
||||
StandardEvaluationContext context = new StandardEvaluationContext();
|
||||
context.setRootObject(principal);
|
||||
context.setVariable("this", principal);
|
||||
|
||||
Expression expression = this.parser.parseExpression(expressionToParse);
|
||||
principal = expression.getValue(context);
|
||||
}
|
||||
|
||||
if (principal != null
|
||||
&& !parameter.getParameterType().isAssignableFrom(principal.getClass())) {
|
||||
AuthenticationPrincipal authPrincipal = findMethodAnnotation(
|
||||
AuthenticationPrincipal.class, parameter);
|
||||
if (authPrincipal.errorOnInvalidType()) {
|
||||
throw new ClassCastException(principal + " is not assignable to "
|
||||
+ parameter.getParameterType());
|
||||
|
||||
+80
-1
@@ -116,6 +116,24 @@ public class AuthenticationPrincipalArgumentResolverTests {
|
||||
expectedPrincipal);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveArgumentSpel() throws Exception {
|
||||
CustomUserPrincipal principal = new CustomUserPrincipal();
|
||||
setAuthenticationPrincipal(principal);
|
||||
this.expectedPrincipal = principal.property;
|
||||
assertThat(this.resolver.resolveArgument(showUserSpel(), null))
|
||||
.isEqualTo(this.expectedPrincipal);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveArgumentSpelCopy() throws Exception {
|
||||
CopyUserPrincipal principal = new CopyUserPrincipal("property");
|
||||
setAuthenticationPrincipal(principal);
|
||||
Object resolveArgument = this.resolver.resolveArgument(showUserSpelCopy(), null);
|
||||
assertThat(resolveArgument).isEqualTo(principal);
|
||||
assertThat(resolveArgument).isNotSameAs(principal);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveArgumentNullOnInvalidType() throws Exception {
|
||||
setAuthenticationPrincipal(new CustomUserPrincipal());
|
||||
@@ -170,6 +188,14 @@ public class AuthenticationPrincipalArgumentResolverTests {
|
||||
return getMethodParameter("showUserCustomAnnotation", CustomUserPrincipal.class);
|
||||
}
|
||||
|
||||
private MethodParameter showUserSpel() {
|
||||
return getMethodParameter("showUserSpel", String.class);
|
||||
}
|
||||
|
||||
private MethodParameter showUserSpelCopy() {
|
||||
return getMethodParameter("showUserSpelCopy", CopyUserPrincipal.class);
|
||||
}
|
||||
|
||||
private MethodParameter showUserAnnotationObject() {
|
||||
return getMethodParameter("showUserAnnotation", Object.class);
|
||||
}
|
||||
@@ -218,9 +244,62 @@ public class AuthenticationPrincipalArgumentResolverTests {
|
||||
|
||||
public void showUserAnnotation(@AuthenticationPrincipal Object user) {
|
||||
}
|
||||
|
||||
public void showUserSpel(
|
||||
@AuthenticationPrincipal(expression = "property") String user) {
|
||||
}
|
||||
|
||||
public void showUserSpelCopy(
|
||||
@AuthenticationPrincipal(expression = "new org.springframework.security.messaging.context.AuthenticationPrincipalArgumentResolverTests$CopyUserPrincipal(#this)") CopyUserPrincipal user) {
|
||||
}
|
||||
}
|
||||
|
||||
private static class CustomUserPrincipal {
|
||||
static class CustomUserPrincipal {
|
||||
public final String property = "property";
|
||||
}
|
||||
|
||||
static class CopyUserPrincipal {
|
||||
public final String property;
|
||||
|
||||
CopyUserPrincipal(String property) {
|
||||
this.property = property;
|
||||
}
|
||||
|
||||
public CopyUserPrincipal(CopyUserPrincipal toCopy) {
|
||||
this.property = toCopy.property;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result
|
||||
+ ((this.property == null) ? 0 : this.property.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
CopyUserPrincipal other = (CopyUserPrincipal) obj;
|
||||
if (this.property == null) {
|
||||
if (other.property != null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (!this.property.equals(other.property)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private void setAuthenticationPrincipal(Object principal) {
|
||||
|
||||
Reference in New Issue
Block a user