1
0
mirror of synced 2026-05-22 21:33:16 +00:00

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:
Rob Winch
2016-05-03 15:42:04 -05:00
committed by Joe Grandja
parent 78bf6e2bd5
commit 9745de9510
6 changed files with 267 additions and 9 deletions
@@ -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());
@@ -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) {