SEC-2151: Support binding method arguments with Annotations
This allow utilizing method arguments for method access control on interfaces prior to JDK 8.
This commit is contained in:
@@ -139,38 +139,88 @@
|
||||
application)<programlisting language="java">
|
||||
@PreAuthorize("hasRole('ROLE_USER')")
|
||||
public void create(Contact contact);</programlisting>which
|
||||
means that access will only be allowed for users with the role "ROLE_USER".
|
||||
Obviously the same thing could easily be achieved using a traditional
|
||||
configuration and a simple configuration attribute for the required role. But
|
||||
what
|
||||
about:<programlisting language="java">
|
||||
@PreAuthorize("hasPermission(#contact, 'admin')")
|
||||
public void deletePermission(Contact contact, Sid recipient, Permission permission);</programlisting>Here
|
||||
we're actually using a method argument as part of the expression to decide
|
||||
whether the current user has the <quote>admin</quote>permission for the given
|
||||
contact. The built-in <literal>hasPermission()</literal> expression is linked
|
||||
into the Spring Security ACL module through the application context, as we'll
|
||||
<link linkend="el-permission-evaluator">see below</link>. You can access any
|
||||
of the method arguments by name as expression variables, provided your code has
|
||||
debug information compiled in. Any Spring-EL functionality is available within
|
||||
the expression, so you can also access properties on the arguments. For example,
|
||||
if you wanted a particular method to only allow access to a user whose username
|
||||
matched that of the contact, you could write</para>
|
||||
<programlisting language="java">
|
||||
@PreAuthorize("#contact.name == authentication.name")
|
||||
public void doSomething(Contact contact);</programlisting>
|
||||
<para>Here we are accessing another built–in expression, <literal>authentication</literal>,
|
||||
which is the <interfacename>Authentication</interfacename> stored in the
|
||||
security context. You can also access its <quote>principal</quote> property
|
||||
directly, using the expression <literal>principal</literal>. The value will
|
||||
often be a <interfacename>UserDetails</interfacename> instance, so you might use an
|
||||
expression like <literal>principal.username</literal> or
|
||||
<literal>principal.enabled</literal>.</para>
|
||||
<para>Less commonly, you may wish to perform an access-control check after the
|
||||
method has been invoked. This can be achieved using the
|
||||
<literal>@PostAuthorize</literal> annotation. To access the return value from a
|
||||
method, use the built–in name <literal>returnObject</literal> in the
|
||||
expression.</para>
|
||||
means that access will only be allowed for users with the role "ROLE_USER".</para>
|
||||
<section xml:id="el-pre-post-annotations-arguments">
|
||||
<title>Resolving method arguments</title>
|
||||
<para>Obviously the same thing could easily be achieved using a traditional
|
||||
configuration and a simple configuration attribute for the required role. But
|
||||
what
|
||||
about:<programlisting language="java">
|
||||
@PreAuthorize("hasPermission(#contact, 'admin')")
|
||||
public void deletePermission(Contact contact, Sid recipient, Permission permission);</programlisting>Here
|
||||
we're actually using a method argument as part of the expression to decide
|
||||
whether the current user has the <quote>admin</quote>permission for the given
|
||||
contact. The built-in <literal>hasPermission()</literal> expression is linked
|
||||
into the Spring Security ACL module through the application context, as we'll
|
||||
<link linkend="el-permission-evaluator">see below</link>. You can access any
|
||||
of the method arguments by name as expression variables.</para>
|
||||
<para>There are a number of ways in which Spring Security can resolve the method arguments. Spring Security
|
||||
uses <classname>DefaultSecurityParameterNameDiscoverer</classname> to discover the parameter names. By default,
|
||||
the following options are tried for a method as a whole.
|
||||
<orderedlist inheritnum="ignore" continuation="restarts">
|
||||
<listitem>
|
||||
<para>If Spring Security's <literal>@P</literal> annotation is present on a single argument to the method,
|
||||
the value will be used. This is useful for interfaces compiled with a JDK prior to JDK 8 which do not contain
|
||||
any information about the parameter names. For example: <programlisting language="java">
|
||||
import org.springframework.security.access.method.P;
|
||||
|
||||
...
|
||||
|
||||
@PreAuthorize("#c.name == authentication.name")
|
||||
public void doSomething(@P("c") Contact contact);</programlisting></para>
|
||||
<para>Behind the scenes this use implemented using <classname>AnnotationParameterNameDiscoverer</classname> which
|
||||
can be customized to support the value attribute of any specified annotation.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>If Spring Data's <literal>@Param</literal> annotation is present on at least one parameter for the method,
|
||||
the value will be used. This is useful for interfaces compiled with a JDK prior to JDK 8 which do not contain
|
||||
any information about the parameter names. For example: <programlisting language="java">
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
...
|
||||
|
||||
@PreAuthorize("#n == authentication.name")
|
||||
Contact findContactByName(@Param("n") String name);</programlisting></para>
|
||||
<para>Behind the scenes this use implemented using <classname>AnnotationParameterNameDiscoverer</classname> which
|
||||
can be customized to support the value attribute of any specified annotation.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>If JDK 8 was used to compile the source with the -parameters argument and Spring 4+ is being used, then
|
||||
the standard JDK reflection API is used to discover the parameter names. This works on both classes and
|
||||
interfaces.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Last, if the code was compiled with the debug symbols, the parameter names will be discovered using
|
||||
the debug symbols. This will not work for interfaces since they do not have debug information about the
|
||||
parameter names. For interfaces, annotations or the JDK 8 approach must be used.</para>
|
||||
</listitem>
|
||||
</orderedlist></para>
|
||||
</section>
|
||||
<section xml:id="el-pre-post-annotations-spel">
|
||||
<title>Method Expressions and SpEL</title>
|
||||
<para>Any Spring-EL functionality is available within
|
||||
the expression, so you can also access properties on the arguments. For example,
|
||||
if you wanted a particular method to only allow access to a user whose username
|
||||
matched that of the contact, you could write</para>
|
||||
<programlisting language="java">
|
||||
@PreAuthorize("#contact.name == authentication.name")
|
||||
public void doSomething(Contact contact);</programlisting>
|
||||
<para>Here we are accessing another built–in expression, <literal>authentication</literal>,
|
||||
which is the <interfacename>Authentication</interfacename> stored in the
|
||||
security context. You can also access its <quote>principal</quote> property
|
||||
directly, using the expression <literal>principal</literal>. The value will
|
||||
often be a <interfacename>UserDetails</interfacename> instance, so you might use an
|
||||
expression like <literal>principal.username</literal> or
|
||||
<literal>principal.enabled</literal>.</para>
|
||||
</section>
|
||||
<section xml:id="el-pre-post-annotations-post">
|
||||
<title>Accessing the return value</title>
|
||||
<para>Less commonly, you may wish to perform an access-control check after the
|
||||
method has been invoked. This can be achieved using the
|
||||
<literal>@PostAuthorize</literal> annotation. To access the return value from a
|
||||
method, use the built–in name <literal>returnObject</literal> in the
|
||||
expression.</para>
|
||||
</section>
|
||||
</section>
|
||||
<section>
|
||||
<title>Filtering using <literal>@PreFilter</literal> and
|
||||
|
||||
Reference in New Issue
Block a user