Hello Bryan, Les, list,
I was trying today a little proof of concept, basically trying to access member
vars which is what my team is firstly interested for. Scanning for the
annotations and using a special instance declaration prefix (I used "#") I
could annotate my methods as:
@RequiresPermissions({"forum:readTopic:#topicID"})
and by modifying BeforeAdviceMethodInvocationAdapter as:
Map<String, String> annotationSub = new HashMap<String, String>();
RequiresPermissions annotation =
((MethodSignature)aJoinPoint.getSignature()).getMethod().getAnnotation(RequiresPermissions.class);
for (String annotationVal : annotation.value()) {
if (annotationVal.matches(".*:.*:#.*")) {
String toSub = annotationVal.substring(annotationVal.lastIndexOf(":")
+ 2);
if (!annotationSub.containsKey(toSub)) {
annotationSub.put(toSub,
(String)PropertyUtils.getProperty(aJoinPoint.getThis(), toSub));
}
}
}
I could therefore end up with a map with key=the original annotation instance
name (i.e. "topicID") and a value=the result from getTopicID() method of the
annotated class. Note: The map may need to be enhanced with extra info or
according to the possible answer below be replaced altogether; for now it just
provides a place to hold the data acquired in runtime.
The question now is how to replace the original annotation with the updated one
(that can be re-constructed using the above Map). At a glance, I see the
following options:
1/ Dynamically update the original class annotation. As far as I know, it is
not possible to change an annotation's value at runtime unless you use
something like Javassist. Wouldn't that be of an overkill, especially
considering that such security checks take place for every single user action?
2/ Find a way to construct a new method signature (updated using the Map above)
to pass it to BeforeAdviceMethodInvocationAdapter's constructor. As far as I
know this is not really an option considering that (the original) annotations
end up in the bytecode.
3/ Modify Shiro's AuthorizingMethodInterceptor with an overloaded invoke() that
takes into account the above Map (yikes!).
4/ Some AspectJ-magic? :)
5/ ???
This is just some food for thought. If you have any ideas/suggestions I would
gladly experiment some more.
-n-
p.s. In a similar fashion, annotated method's args can also be supported using
aJoinPoint.getArgs() in BeforeAdviceMethodInvocationAdapter. Of course, as
Bryan correctly mentioned, you need debug info in your bytecode to access the
actual names of the args but I guess BeforeAdviceMethodInvocationAdapter could
be modified accordingly to support both approaches, e.g. "@topicID" when debug
info is available and something like "@@arg0" when it's not or even something
more crazy :) like "@topicID/0" to allow one set of annotations to work in all
situations regardless of how the code was built.
On 10 Νοε 2010, at 12:50 π.μ., Bryan Turner wrote:
> Parameter names are available at runtime if the code is compiled with debug
> information (even in production environments, it is not uncommon for the
> release build to include this). Spring uses ASM internally to parse the names
> out of the bytecode, using its LocalVariableTableParameterNameDiscoverer. For
> Spring-based systems that always compile with debugging information, this
> might be a solid approach.
>
> Otherwise, a fallback approach that allows referring to parameters by number
> (1-based) or index (0-based) might be a good catch-all solution that would
> work in any AOP environment.
>
> I'd be happy to help contribute an implementation of this feature.
>
> Bryan
>
> Date: Tue, 9 Nov 2010 14:30:10 -0800
> Subject: Re: Shiro + AspectJ - accessing variables in annotations
> From: [email protected]
> To: [email protected]
>
> Hi Nassos,
>
> This is something that we've wanted for Shiro annotations for a long time,
> but no one has built it yet. I'm not sure off the top of my head how to go
> about doing this, but I remember seeing Spring AOP have the ability to
> reference method arguments by parameter name (this was a while ago, but I
> know it is possible). Since that information is lost at runtime, I think is
> a compile time feature. That, or you annotate method parameters that could
> be accessed at runtime.
>
> I think it would be great if someone wanted to help with this!
>
> Cheers,
>
> Les
>
> On Tue, Nov 9, 2010 at 5:49 AM, Nassos A. Michas <[email protected]>
> wrote:
> Hello,
>
> when using Shiro in a non-Spring webapp using the Shiro annotations and
> AspectJ (as per the Shiro sample application) is it possible to somehow have
> access to the member (or even the annotated method's) variables? For example,
> am I somehow able to write something like:
> @RequiresPermission("forum:readTopic:#forumID")
> void readTopic(String forumID) {
> ...
> }
> or even,
> @RequiresPermission("forum:readTopic:#forum.forumID")
> void readTopic(MyBean forum) {
> ...
> }
>
> If this is more of an AspectJ-related question please accept my apologies as
> I'm not a big AspectJ user.
>
>
> Thanks!
>
> -n-