Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p><strong>Preamble:</strong> Since Spring-Security 3.2 there is a nice annotation <code>@AuthenticationPrincipal</code> described at the end of this answer. This is the best way to go when you use Spring-Security >= 3.2.</p> <p>When you:</p> <ul> <li>use an older version of Spring-Security,</li> <li>need to load your custom User Object from the Database by some information (like the login or id) stored in the principal or</li> <li>want to learn how a <code>HandlerMethodArgumentResolver</code> or <code>WebArgumentResolver</code> can solve this in an elegant way, or just want to an learn the background behind <code>@AuthenticationPrincipal</code> and <code>AuthenticationPrincipalArgumentResolver</code> (because it is based on a <code>HandlerMethodArgumentResolver</code>)</li> </ul> <p>then keep on reading — else just use <code>@AuthenticationPrincipal</code> and thank to Rob Winch (Author of <code>@AuthenticationPrincipal</code>) and <a href="http://stackoverflow.com/a/22857426/280244">Lukas Schmelzeisen</a> (for his answer).</p> <p><em>(BTW: My answer is a bit older (January 2012), so it was <a href="http://stackoverflow.com/a/22857426/280244">Lukas Schmelzeisen</a> that come up as the first one with the <code>@AuthenticationPrincipal</code> annotation solution base on Spring Security 3.2.)</em></p> <hr> <p>Then you can use in your controller</p> <pre><code>public ModelAndView someRequestHandler(Principal principal) { User activeUser = (User) ((Authentication) principal).getPrincipal(); ... } </code></pre> <hr> <p>That is ok if you need it once. But if you need it several times its ugly because it pollutes your controller with infrastructure details, that normally should be hidden by the framework.</p> <p>So what you may really want is to have a controller like this:</p> <pre><code>public ModelAndView someRequestHandler(@ActiveUser User activeUser) { ... } </code></pre> <p>Therefore you only need to implement a <a href="http://static.springsource.org/spring/docs/3.0.x/javadoc-api/" rel="nofollow noreferrer"><code>WebArgumentResolver</code></a>. It has a method</p> <pre><code>Object resolveArgument(MethodParameter methodParameter, NativeWebRequest webRequest) throws Exception </code></pre> <p>That gets the web request (second parameter) and must return the <code>User</code> if its feels responsible for the method argument (the first parameter).</p> <p><em>Since Spring 3.1 there is a new concept called <a href="http://static.springsource.org/spring/docs/3.1.x/javadoc-api/org/springframework/web/method/support/HandlerMethodArgumentResolver.html" rel="nofollow noreferrer"><code>HandlerMethodArgumentResolver</code></a>. If you use Spring 3.1+ then you should use it. (It is described in the next section of this answer))</em></p> <pre><code>public class CurrentUserWebArgumentResolver implements WebArgumentResolver{ Object resolveArgument(MethodParameter methodParameter, NativeWebRequest webRequest) { if(methodParameter is for type User &amp;&amp; methodParameter is annotated with @ActiveUser) { Principal principal = webRequest.getUserPrincipal(); return (User) ((Authentication) principal).getPrincipal(); } else { return WebArgumentResolver.UNRESOLVED; } } } </code></pre> <p>You need to define the Custom Annotation -- You can skip it if every instance of User should always be taken from the security context, but is never a command object.</p> <pre><code>@Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface ActiveUser {} </code></pre> <p>In the configuration you only need to add this:</p> <pre><code>&lt;bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" id="applicationConversionService"&gt; &lt;property name="customArgumentResolver"&gt; &lt;bean class="CurrentUserWebArgumentResolver"/&gt; &lt;/property&gt; &lt;/bean&gt; </code></pre> <p>@See: <a href="http://karthikg.wordpress.com/2009/11/08/learn-to-customize-spring-mvc-controller-method-arguments/" rel="nofollow noreferrer">Learn to customize Spring MVC @Controller method arguments</a> </p> <p><em>It should be noted that if you're using Spring 3.1, they recommend HandlerMethodArgumentResolver over WebArgumentResolver. - see comment by Jay</em></p> <hr> <h2><strong>The same with <code>HandlerMethodArgumentResolver</code> for Spring 3.1+</strong></h2> <pre><code>public class CurrentUserHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver { @Override public boolean supportsParameter(MethodParameter methodParameter) { return methodParameter.getParameterAnnotation(ActiveUser.class) != null &amp;&amp; methodParameter.getParameterType().equals(User.class); } @Override public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { if (this.supportsParameter(methodParameter)) { Principal principal = webRequest.getUserPrincipal(); return (User) ((Authentication) principal).getPrincipal(); } else { return WebArgumentResolver.UNRESOLVED; } } } </code></pre> <p>In the configuration, you need to add this</p> <pre><code>&lt;mvc:annotation-driven&gt; &lt;mvc:argument-resolvers&gt; &lt;bean class="CurrentUserHandlerMethodArgumentResolver"/&gt; &lt;/mvc:argument-resolvers&gt; &lt;/mvc:annotation-driven&gt; </code></pre> <p>@See <a href="http://blog.42.nl/articles/leveraging-the-spring-mvc-3-1-handlermethodargumentresolver-interface/" rel="nofollow noreferrer">Leveraging the Spring MVC 3.1 HandlerMethodArgumentResolver interface</a></p> <hr> <h2><strong>Spring-Security 3.2 Solution</strong></h2> <p>Spring Security 3.2 (do not confuse with Spring 3.2) has own build in solution: <a href="http://docs.spring.io/spring-security/site/docs/3.2.5.RELEASE/apidocs/org/springframework/security/web/bind/annotation/AuthenticationPrincipal.html" rel="nofollow noreferrer"><code>@AuthenticationPrincipal</code></a> (<code>org.springframework.security.web.bind.annotation.AuthenticationPrincipal</code>) . This is nicely described in <a href="http://stackoverflow.com/a/22857426/280244">Lukas Schmelzeisen`s answer</a></p> <p>It is just writing</p> <pre><code>ModelAndView someRequestHandler(@AuthenticationPrincipal User activeUser) { ... } </code></pre> <p>To get this working you need to register the <code>AuthenticationPrincipalArgumentResolver</code> (<code>org.springframework.security.web.bind.support.AuthenticationPrincipalArgumentResolver</code>) : either by "activating" <code>@EnableWebMvcSecurity</code> or by registering this bean within <code>mvc:argument-resolvers</code> - the same way I described it with may Spring 3.1 solution above.</p> <p>@See <a href="http://docs.spring.io/spring-security/site/docs/3.2.3.RELEASE/reference/htmlsingle/#mvc-authentication-principal" rel="nofollow noreferrer">Spring Security 3.2 Reference, Chapter 11.2. @AuthenticationPrincipal</a></p> <hr> <h2><strong>Spring-Security 4.0 Solution</strong></h2> <p>It works like the Spring 3.2 solution, but in Spring 4.0 the <code>@AuthenticationPrincipal</code> and <code>AuthenticationPrincipalArgumentResolver</code> was "moved" to an other package:</p> <ul> <li><a href="https://docs.spring.io/spring-security/site/docs/5.0.4.RELEASE/api/org/springframework/security/core/annotation/AuthenticationPrincipal.html" rel="nofollow noreferrer"><code>org.springframework.security.core.annotation.AuthenticationPrincipal</code></a></li> <li><a href="https://docs.spring.io/spring-security/site/docs/5.0.4.RELEASE/api/org/springframework/security/web/method/annotation/AuthenticationPrincipalArgumentResolver.html" rel="nofollow noreferrer"><code>org.springframework.security.web.method.annotation.AuthenticationPrincipalArgumentResolver</code></a></li> </ul> <p>(But the old classes in its old packges still exists, so do not mix them!)</p> <p>It is just writing</p> <pre><code>import org.springframework.security.core.annotation.AuthenticationPrincipal; ModelAndView someRequestHandler(@AuthenticationPrincipal User activeUser) { ... } </code></pre> <p>To get this working you need to register the (<code>org.springframework.security.web.method.annotation.</code>) <code>AuthenticationPrincipalArgumentResolver</code> : either by "activating" <code>@EnableWebMvcSecurity</code> or by registering this bean within <code>mvc:argument-resolvers</code> - the same way I described it with may Spring 3.1 solution above.</p> <pre><code>&lt;mvc:annotation-driven&gt; &lt;mvc:argument-resolvers&gt; &lt;bean class="org.springframework.security.web.method.annotation.AuthenticationPrincipalArgumentResolver" /&gt; &lt;/mvc:argument-resolvers&gt; &lt;/mvc:annotation-driven&gt; </code></pre> <p>@See <a href="https://docs.spring.io/spring-security/site/docs/5.0.4.RELEASE/reference/htmlsingle/#mvc-authentication-principal" rel="nofollow noreferrer">Spring Security 5.0 Reference, Chapter 39.3 @AuthenticationPrincipal</a></p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload