Shiro的AOP横切模式-注解权限控制

AuthorizationAttributeSourceAdvisor切入点

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.apache.shiro.spring.security.interceptor;

import org.apache.shiro.authz.annotation.*;
import org.apache.shiro.mgt.SecurityManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor;
import org.springframework.core.annotation.AnnotationUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

/**
 * TODO - complete JavaDoc
 *
 * @since 0.1
 */
@SuppressWarnings({"unchecked"})
public class AuthorizationAttributeSourceAdvisor extends StaticMethodMatcherPointcutAdvisor {

    private static final Logger log = LoggerFactory.getLogger(AuthorizationAttributeSourceAdvisor.class);

    // 权限控制支持的注解
    private static final Class<? extends Annotation>[] AUTHZ_ANNOTATION_CLASSES =
            new Class[] {
                    RequiresPermissions.class, RequiresRoles.class,
                    RequiresUser.class, RequiresGuest.class, RequiresAuthentication.class
            };

    protected SecurityManager securityManager = null;

    /**
     * Create a new AuthorizationAttributeSourceAdvisor.
     *
     * 构造方法创建方法拦截器并设置为通知
     */
    public AuthorizationAttributeSourceAdvisor() {
        setAdvice(new AopAllianceAnnotationsAuthorizingMethodInterceptor());
    }

    public SecurityManager getSecurityManager() {
        return securityManager;
    }

    public void setSecurityManager(org.apache.shiro.mgt.SecurityManager securityManager) {
        this.securityManager = securityManager;
    }

    /**
     * Returns <tt>true</tt> if the method or the class has any Shiro annotations, false otherwise.
     * The annotations inspected are:
     * <ul>
     * <li>{@link org.apache.shiro.authz.annotation.RequiresAuthentication RequiresAuthentication}</li>
     * <li>{@link org.apache.shiro.authz.annotation.RequiresUser RequiresUser}</li>
     * <li>{@link org.apache.shiro.authz.annotation.RequiresGuest RequiresGuest}</li>
     * <li>{@link org.apache.shiro.authz.annotation.RequiresRoles RequiresRoles}</li>
     * <li>{@link org.apache.shiro.authz.annotation.RequiresPermissions RequiresPermissions}</li>
     * </ul>
     *
     * @param method      the method to check for a Shiro annotation
     * @param targetClass the class potentially declaring Shiro annotations
     * @return <tt>true</tt> if the method has a Shiro annotation, false otherwise.
     * @see org.springframework.aop.MethodMatcher#matches(java.lang.reflect.Method, Class)
     *
     *
     * 切入点方法匹配方式
     */
    public boolean matches(Method method, Class targetClass) {
        Method m = method;

        if ( isAuthzAnnotationPresent(m) ) {
            return true;
        }

        //The ‘method‘ parameter could be from an interface that doesn‘t have the annotation.
        //Check to see if the implementation has it.
        if ( targetClass != null) {
            try {
                m = targetClass.getMethod(m.getName(), m.getParameterTypes());
                return isAuthzAnnotationPresent(m) || isAuthzAnnotationPresent(targetClass);
            } catch (NoSuchMethodException ignored) {
                //default return value is false.  If we can‘t find the method, then obviously
                //there is no annotation, so just use the default return value.
            }
        }

        return false;
    }

    // 判断目标方法上是否有注解
    private boolean isAuthzAnnotationPresent(Class<?> targetClazz) {
        for( Class<? extends Annotation> annClass : AUTHZ_ANNOTATION_CLASSES ) {
            Annotation a = AnnotationUtils.findAnnotation(targetClazz, annClass);
            if ( a != null ) {
                return true;
            }
        }
        return false;
    }

    // 判断目标方法上是否有注解
    private boolean isAuthzAnnotationPresent(Method method) {
        for( Class<? extends Annotation> annClass : AUTHZ_ANNOTATION_CLASSES ) {
            Annotation a = AnnotationUtils.findAnnotation(method, annClass);
            if ( a != null ) {
                return true;
            }
        }
        return false;
    }

}

AopAllianceAnnotationsAuthorizingMethodInterceptor方法拦截器

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.apache.shiro.spring.security.interceptor;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.shiro.aop.AnnotationResolver;
import org.apache.shiro.authz.aop.*;
import org.apache.shiro.spring.aop.SpringAnnotationResolver;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * Allows Shiro Annotations to work in any <a href="http://aopalliance.sourceforge.net/">AOP Alliance</a>
 * specific implementation environment (for example, Spring).
 *
 * @since 0.2
 */
public class AopAllianceAnnotationsAuthorizingMethodInterceptor
        extends AnnotationsAuthorizingMethodInterceptor implements MethodInterceptor {

    // 构造方法内创建AnnotationResolver注解解析器(主要是判断方法上是否有注解)
    // 创建AnnotationMethodInterceptor注解方法拦截器
    public AopAllianceAnnotationsAuthorizingMethodInterceptor() {
        List<AuthorizingAnnotationMethodInterceptor> interceptors =
                new ArrayList<AuthorizingAnnotationMethodInterceptor>(5);

        //use a Spring-specific Annotation resolver - Spring‘s AnnotationUtils is nicer than the
        //raw JDK resolution process.
        AnnotationResolver resolver = new SpringAnnotationResolver();
        //we can re-use the same resolver instance - it does not retain state:
        interceptors.add(new RoleAnnotationMethodInterceptor(resolver));
        interceptors.add(new PermissionAnnotationMethodInterceptor(resolver));
        interceptors.add(new AuthenticatedAnnotationMethodInterceptor(resolver));
        interceptors.add(new UserAnnotationMethodInterceptor(resolver));
        interceptors.add(new GuestAnnotationMethodInterceptor(resolver));
     // 为子类AnnotationsAuthorizingMethodInterceptor注入方法拦截器
        setMethodInterceptors(interceptors);
    }
    /**
     * Creates a {@link MethodInvocation MethodInvocation} that wraps an
     * {@link org.aopalliance.intercept.MethodInvocation org.aopalliance.intercept.MethodInvocation} instance,
     * enabling Shiro Annotations in <a href="http://aopalliance.sourceforge.net/">AOP Alliance</a> environments
     * (Spring, etc).
     *
     * @param implSpecificMethodInvocation AOP Alliance {@link org.aopalliance.intercept.MethodInvocation MethodInvocation}
     * @return a Shiro {@link MethodInvocation MethodInvocation} instance that wraps the AOP Alliance instance.
     *
     * 将org.aopalliance.intercept.MethodInvocation包装成org.apache.shiro.aop.MethodInvocation
     */
    protected org.apache.shiro.aop.MethodInvocation createMethodInvocation(Object implSpecificMethodInvocation) {
        final MethodInvocation mi = (MethodInvocation) implSpecificMethodInvocation;

        return new org.apache.shiro.aop.MethodInvocation() {
            public Method getMethod() {
                return mi.getMethod();
            }

            public Object[] getArguments() {
                return mi.getArguments();
            }

            public String toString() {
                return "Method invocation [" + mi.getMethod() + "]";
            }

            public Object proceed() throws Throwable {
                return mi.proceed();
            }

            public Object getThis() {
                return mi.getThis();
            }
        };
    }

    /**
     * Simply casts the method argument to an
     * {@link org.aopalliance.intercept.MethodInvocation org.aopalliance.intercept.MethodInvocation} and then
     * calls <code>methodInvocation.{@link org.aopalliance.intercept.MethodInvocation#proceed proceed}()</code>
     *
     * @param aopAllianceMethodInvocation the {@link org.aopalliance.intercept.MethodInvocation org.aopalliance.intercept.MethodInvocation}
     * @return the {@link org.aopalliance.intercept.MethodInvocation#proceed() org.aopalliance.intercept.MethodInvocation.proceed()} method call result.
     * @throws Throwable if the underlying AOP Alliance <code>proceed()</code> call throws a <code>Throwable</code>.
     */
    protected Object continueInvocation(Object aopAllianceMethodInvocation) throws Throwable {
        MethodInvocation mi = (MethodInvocation) aopAllianceMethodInvocation;
        return mi.proceed();
    }

    /**
     * Creates a Shiro {@link MethodInvocation MethodInvocation} instance and then immediately calls
     * {@link org.apache.shiro.authz.aop.AuthorizingMethodInterceptor#invoke super.invoke}.
     *
     * @param methodInvocation the AOP Alliance-specific <code>methodInvocation</code> instance.
     * @return the return value from invoking the method invocation.
     * @throws Throwable if the underlying AOP Alliance method invocation throws a <code>Throwable</code>.
     *
     * 对MethodInvocation进行包装之后调用父类的invoke方法
     */
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        org.apache.shiro.aop.MethodInvocation mi = createMethodInvocation(methodInvocation);
        return super.invoke(mi);
    }
}

AuthorizingMethodInterceptor权限方法拦截器,很抽象

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.apache.shiro.authz.aop;

import org.apache.shiro.aop.MethodInterceptorSupport;
import org.apache.shiro.aop.MethodInvocation;
import org.apache.shiro.authz.AuthorizationException;

/**
 * Basic abstract class to support intercepting methods that perform authorization (access control) checks.
 *
 * @since 0.9
 */
public abstract class AuthorizingMethodInterceptor extends MethodInterceptorSupport {

    /**
     * Invokes the specified method (<code>methodInvocation.{@link org.apache.shiro.aop.MethodInvocation#proceed proceed}()</code>
     * if authorization is allowed by first
     * calling {@link #assertAuthorized(org.apache.shiro.aop.MethodInvocation) assertAuthorized}.
     */
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        assertAuthorized(methodInvocation);
        return methodInvocation.proceed();
    }

    /**
     * Asserts that the specified MethodInvocation is allowed to continue by performing any necessary authorization
     * (access control) checks first.
     * @param methodInvocation the <code>MethodInvocation</code> to invoke.
     * @throws AuthorizationException if the <code>methodInvocation</code> should not be allowed to continue/execute.
     *
     * 判断是否有权限的事交给具体的子类(AnnotationsAuthorizingMethodInterceptor)去处理
     */
    protected abstract void assertAuthorized(MethodInvocation methodInvocation) throws AuthorizationException;

}

AnnotationsAuthorizingMethodInterceptor注解方式权限方法拦截器,很具体

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.apache.shiro.authz.aop;

import java.util.ArrayList;
import java.util.Collection;

import org.apache.shiro.aop.MethodInvocation;
import org.apache.shiro.authz.AuthorizationException;

/**
 * An <tt>AnnotationsAuthorizingMethodInterceptor</tt> is a MethodInterceptor that asserts a given method is authorized
 * to execute based on one or more configured <tt>AuthorizingAnnotationMethodInterceptor</tt>s.
 *
 * <p>This allows multiple annotations on a method to be processed before the method
 * executes, and if any of the <tt>AuthorizingAnnotationMethodInterceptor</tt>s indicate that the method should not be
 * executed, an <tt>AuthorizationException</tt> will be thrown, otherwise the method will be invoked as expected.
 *
 * <p>It is essentially a convenience mechanism to allow multiple annotations to be processed in a single method
 * interceptor.
 *
 * @since 0.2
 */
public abstract class AnnotationsAuthorizingMethodInterceptor extends AuthorizingMethodInterceptor {

    /**
     * The method interceptors to execute for the annotated method.
     */
    protected Collection<AuthorizingAnnotationMethodInterceptor> methodInterceptors;

    /**
     * Default no-argument constructor that defaults the
     * {@link #methodInterceptors methodInterceptors} attribute to contain two interceptors by default - the
     * {@link RoleAnnotationMethodInterceptor RoleAnnotationMethodInterceptor} and the
     * {@link PermissionAnnotationMethodInterceptor PermissionAnnotationMethodInterceptor} to
     * support role and permission annotations.
     *
     * 构造时默认创建5个权限注解方法拦截器
     * 但是又提供了setMethodInterceptors(Collection<AuthorizingAnnotationMethodInterceptor> methodInterceptors)注入更扩展的权限注解方法拦截器
     */
    public AnnotationsAuthorizingMethodInterceptor() {
        methodInterceptors = new ArrayList<AuthorizingAnnotationMethodInterceptor>(5);
        methodInterceptors.add(new RoleAnnotationMethodInterceptor());
        methodInterceptors.add(new PermissionAnnotationMethodInterceptor());
        methodInterceptors.add(new AuthenticatedAnnotationMethodInterceptor());
        methodInterceptors.add(new UserAnnotationMethodInterceptor());
        methodInterceptors.add(new GuestAnnotationMethodInterceptor());
    }

    /**
     * Returns the method interceptors to execute for the annotated method.
     * <p/>
     * Unless overridden by the {@link #setMethodInterceptors(java.util.Collection)} method, the default collection
     * contains a
     * {@link RoleAnnotationMethodInterceptor RoleAnnotationMethodInterceptor} and a
     * {@link PermissionAnnotationMethodInterceptor PermissionAnnotationMethodInterceptor} to
     * support role and permission annotations automatically.
     * @return the method interceptors to execute for the annotated method.
     */
    public Collection<AuthorizingAnnotationMethodInterceptor> getMethodInterceptors() {
        return methodInterceptors;
    }

    /**
     * Sets the method interceptors to execute for the annotated method.
     * @param methodInterceptors the method interceptors to execute for the annotated method.
     * @see #getMethodInterceptors()
     *
     * 可注入具有扩展性的权限注解方法拦截器
     * 子类AopAllianceAnnotationsAuthorizingMethodInterceptor构造时调用了该方法
     */
    public void setMethodInterceptors(Collection<AuthorizingAnnotationMethodInterceptor> methodInterceptors) {
        this.methodInterceptors = methodInterceptors;
    }

    /**
     * Iterates over the internal {@link #getMethodInterceptors() methodInterceptors} collection, and for each one,
     * ensures that if the interceptor
     * {@link AuthorizingAnnotationMethodInterceptor#supports(org.apache.shiro.aop.MethodInvocation) supports}
     * the invocation, that the interceptor
     * {@link AuthorizingAnnotationMethodInterceptor#assertAuthorized(org.apache.shiro.aop.MethodInvocation) asserts}
     * that the invocation is authorized to proceed.
     *
     * 遍历各个权限注解方法拦截器如new RoleAnnotationMethodInterceptor(new SpringAnnotationResolver())
     * 此时是注解权限方法拦截器内使用权限注解方法拦截器判断是否有权限,具体的判断要权限注解方法拦截器来处理
     */
    protected void assertAuthorized(MethodInvocation methodInvocation) throws AuthorizationException {
        //default implementation just ensures no deny votes are cast:
        Collection<AuthorizingAnnotationMethodInterceptor> aamis = getMethodInterceptors();
        if (aamis != null && !aamis.isEmpty()) {
            for (AuthorizingAnnotationMethodInterceptor aami : aamis) {
                if (aami.supports(methodInvocation)) {
                    aami.assertAuthorized(methodInvocation);
                }
            }
        }
    }
}

AuthorizingAnnotationMethodInterceptor权限注解方法拦截器

先看父类AnnotationMethodInterceptor注解方法拦截器

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.apache.shiro.aop;

import java.lang.annotation.Annotation;

/**
 * MethodInterceptor that inspects a specific annotation on the method invocation before continuing
 * its execution.
 * </p>
 * The annotation is acquired from the {@link MethodInvocation MethodInvocation} via a
 * {@link AnnotationResolver AnnotationResolver} instance that may be configured.  Unless
 * overridden, the default {@code AnnotationResolver} is a
 *
 * @since 0.9
 */
public abstract class AnnotationMethodInterceptor extends MethodInterceptorSupport {

    private AnnotationHandler handler;

    /**
     * The resolver to use to find annotations on intercepted methods.
     *
     * @since 1.1
     */
    private AnnotationResolver resolver;

    /**
     * Constructs an <code>AnnotationMethodInterceptor</code> with the
     * {@link AnnotationHandler AnnotationHandler} that will be used to process annotations of a
     * corresponding type.
     *
     * @param handler the handler to delegate to for processing the annotation.
     *
     * 构造时注入注解处理器和默认的注解解析器
     */
    public AnnotationMethodInterceptor(AnnotationHandler handler) {
        this(handler, new DefaultAnnotationResolver());
    }

    /**
     * Constructs an <code>AnnotationMethodInterceptor</code> with the
     * {@link AnnotationHandler AnnotationHandler} that will be used to process annotations of a
     * corresponding type, using the specified {@code AnnotationResolver} to acquire annotations
     * at runtime.
     *
     * @param handler  the handler to use to process any discovered annotation
     * @param resolver the resolver to use to locate/acquire the annotation
     * @since 1.1
     */
    public AnnotationMethodInterceptor(AnnotationHandler handler, AnnotationResolver resolver) {
        if (handler == null) {
            throw new IllegalArgumentException("AnnotationHandler argument cannot be null.");
        }
        setHandler(handler);
        setResolver(resolver != null ? resolver : new DefaultAnnotationResolver());
    }

    /**
     * Returns the {@code AnnotationHandler} used to perform authorization behavior based on
     * an annotation discovered at runtime.
     *
     * @return the {@code AnnotationHandler} used to perform authorization behavior based on
     *         an annotation discovered at runtime.
     */
    public AnnotationHandler getHandler() {
        return handler;
    }

    /**
     * Sets the {@code AnnotationHandler} used to perform authorization behavior based on
     * an annotation discovered at runtime.
     *
     * @param handler the {@code AnnotationHandler} used to perform authorization behavior based on
     *                an annotation discovered at runtime.
     *
     * 支持扩展的注解处理器
     */
    public void setHandler(AnnotationHandler handler) {
        this.handler = handler;
    }

    /**
     * Returns the {@code AnnotationResolver} to use to acquire annotations from intercepted
     * methods at runtime.  The annotation is then used by the {@link #getHandler handler} to
     * perform authorization logic.
     *
     * @return the {@code AnnotationResolver} to use to acquire annotations from intercepted
     *         methods at runtime.
     * @since 1.1
     */
    public AnnotationResolver getResolver() {
        return resolver;
    }

    /**
     * Returns the {@code AnnotationResolver} to use to acquire annotations from intercepted
     * methods at runtime.  The annotation is then used by the {@link #getHandler handler} to
     * perform authorization logic.
     *
     * @param resolver the {@code AnnotationResolver} to use to acquire annotations from intercepted
     *                 methods at runtime.
     * @since 1.1
     *
     * 支持扩展的注解解析器
     */
    public void setResolver(AnnotationResolver resolver) {
        this.resolver = resolver;
    }

    /**
     * Returns <code>true</code> if this interceptor supports, that is, should inspect, the specified
     * <code>MethodInvocation</code>, <code>false</code> otherwise.
     * <p/>
     * The default implementation simply does the following:
     * <p/>
     * <code>return {@link #getAnnotation(MethodInvocation) getAnnotation(mi)} != null</code>
     *
     * @param mi the <code>MethodInvocation</code> for the method being invoked.
     * @return <code>true</code> if this interceptor supports, that is, should inspect, the specified
     *         <code>MethodInvocation</code>, <code>false</code> otherwise.
     *
     * 判断目标方法上是否有权限注解
     */
    public boolean supports(MethodInvocation mi) {
        return getAnnotation(mi) != null;
    }

    /**
     * Returns the Annotation that this interceptor will process for the specified method invocation.
     * <p/>
     * The default implementation acquires the annotation using an annotation
     * {@link #getResolver resolver} using the internal annotation {@link #getHandler handler}‘s
     * {@link org.apache.shiro.aop.AnnotationHandler#getAnnotationClass() annotationClass}.
     *
     * @param mi the MethodInvocation wrapping the Method from which the Annotation will be acquired.
     * @return the Annotation that this interceptor will process for the specified method invocation.
     *
     * 使用注解解析器获得目标方法上的注解
     */
    protected Annotation getAnnotation(MethodInvocation mi) {
        return getResolver().getAnnotation(mi, getHandler().getAnnotationClass());
    }
}

继续AuthorizingAnnotationMethodInterceptor

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.apache.shiro.authz.aop;

import org.apache.shiro.aop.AnnotationMethodInterceptor;
import org.apache.shiro.aop.AnnotationResolver;
import org.apache.shiro.aop.MethodInvocation;
import org.apache.shiro.authz.AuthorizationException;

/**
 * An <tt>AnnotationMethodInterceptor</tt> that asserts the calling code is authorized to execute the method
 * before allowing the invocation to continue by inspecting code annotations to perform an access control check.
 *
 * @since 0.1
 */
public abstract class AuthorizingAnnotationMethodInterceptor extends AnnotationMethodInterceptor
{

    /**
     * Constructor that ensures the internal <code>handler</code> is set which will be used to perform the
     * authorization assertion checks when a supported annotation is encountered.
     * @param handler the internal <code>handler</code> used to perform authorization assertion checks when a
     * supported annotation is encountered.
     */
    public AuthorizingAnnotationMethodInterceptor( AuthorizingAnnotationHandler handler ) {
        super(handler);
    }

    /**
     *
     * @param handler
     * @param resolver
     * @since 1.1
     *
     * 将注入进来的handler和resolver提供给父类AnnotationMethodInterceptor
     */
    public AuthorizingAnnotationMethodInterceptor( AuthorizingAnnotationHandler handler,
                                                   AnnotationResolver resolver) {
        super(handler, resolver);
    }

    /**
     * Ensures the <code>methodInvocation</code> is allowed to execute first before proceeding by calling the
     * {@link #assertAuthorized(org.apache.shiro.aop.MethodInvocation) assertAuthorized} method first.
     *
     * @param methodInvocation the method invocation to check for authorization prior to allowing it to proceed/execute.
     * @return the return value from the method invocation (the value of {@link org.apache.shiro.aop.MethodInvocation#proceed() MethodInvocation.proceed()}).
     * @throws org.apache.shiro.authz.AuthorizationException if the <code>MethodInvocation</code> is not allowed to proceed.
     * @throws Throwable if any other error occurs.
     */
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        assertAuthorized(methodInvocation);
        return methodInvocation.proceed();
    }

    /**
     * Ensures the calling Subject is authorized to execute the specified <code>MethodInvocation</code>.
     * <p/>
     * As this is an AnnotationMethodInterceptor, this implementation merely delegates to the internal
     * {@link AuthorizingAnnotationHandler AuthorizingAnnotationHandler} by first acquiring the annotation by
     * calling {@link #getAnnotation(MethodInvocation) getAnnotation(methodInvocation)} and then calls
     * {@link AuthorizingAnnotationHandler#assertAuthorized(java.lang.annotation.Annotation) handler.assertAuthorized(annotation)}.
     *
     * @param mi the <code>MethodInvocation</code> to check to see if it is allowed to proceed/execute.
     * @throws AuthorizationException if the method invocation is not allowed to continue/execute.
     *
     * 使用权限注解处理器来处理判断是否具备权限
     */
    public void assertAuthorized(MethodInvocation mi) throws AuthorizationException {
        try {
            ((AuthorizingAnnotationHandler)getHandler()).assertAuthorized(getAnnotation(mi));
        }
        catch(AuthorizationException ae) {
            // Annotation handler doesn‘t know why it was called, so add the information here if possible.
            // Don‘t wrap the exception here since we don‘t want to mask the specific exception, such as
            // UnauthenticatedException etc.
            if (ae.getCause() == null) ae.initCause(new AuthorizationException("Not authorized to invoke method: " + mi.getMethod()));
            throw ae;
        }
    }
}

原文地址:https://www.cnblogs.com/BINGJJFLY/p/9066524.html

时间: 2024-08-01 17:25:09

Shiro的AOP横切模式-注解权限控制的相关文章

spring-security 开启注解权限控制为什么没有效果

如果配置在spring-security中没有权限控制效果,可以配置在springmvc中试试 1 <security:global-method-security pre-post-annotations="enabled"/> 2 <security:global-method-security jsr250-annotations="enabled"/> 3 <security:global-method-security sec

shiro注解权限控制-5个权限注解

RequiresAuthentication: 使用该注解标注的类,实例,方法在访问或调用时,当前Subject必须在当前session中已经过认证 RequiresGuest: 使用该注解标注的类,实例,方法在访问或调用时,当前Subject可以是"gust"身份,不需要经过认证或者在原先的session中存在记录. RequiresPermissions: 当前Subject需要拥有某些特定的权限时,才能执行被该注解标注的方法.如果当前Subject不具有这样的权限,则方法不会被执

spring AOP + 自定义注解实现权限控制小例子

今天看了一下黑马程序员的视频,上面讲到一个使用spring AOP + 自定义注解的方式来实现权限控制的一个小例子,个人觉得还是可以借鉴,整理出来与大家分享. 需求:service层有一些方法,这些方法需要不同的权限才能访问. 实现方案:自定义一个PrivilegeInfo的注解,使用这个注解为service层中的方法进行权限配置,在aop中根据PrivilegeInfo注解的值,判断用户是否拥有访问目标方法的权限,有则访问目标方法,没有则给出提示. 关键技术:自定义注解及注解解析,spring

shiro进行权限控制的四种方式

```我们使用shiro进行权限控制 有以下几种方式 1. URL拦截权限控制:基于filter过滤器实现 我们在spring配置文件中配置shiroFilter时配置 <!--指定URL级别拦截策略 --> <property name="filterChainDefinitions"> <value> /css/ = anon /js/ = anon /images/ = anon /validatecode.jsp = anon /login.

单体物联平台系统(Springboot整合shiro实现多realm多用户表多权限表登陆)

参考实现:http://www.qchcloud.cn/tn/article/30 一.技术框架 本项目基于Spring,整合Apache Shiro框架,实现用户管理和权限控制,主要内容如下: 1.登录(带验证码),包括"记住我"的功能: 2.加密,存储的密码不采用明文: 3.session管理:使用shiro默认的session管理替代Tomcat的HttpSession: 4.shiro拦截器:对静态文件(HTML/JS/CSS等)进行权限控制,无权限则请求不到: 5.后台接口权

036 权限控制介绍 - bos

一.权限概述 1.认证:系统提供的用于识别用户身份的功能,通常登录功能就是认证功能-----让系统知道你是谁?? 2.授权:系统授予用户可以访问哪些功能的许可(证书)----让系统知道你能做什么?? 二.常见的权限控制方式 1.URL拦截权限控制 <1>底层基于拦截器或者过滤器实现 <2>用户访问某一url,在过滤器或拦截器中先判定该url是否需要拦截,若需要,则取出当前登录的用户,判定是否具有足够的权限 2.方法注解权限控制 <1>添加某一注解表示该方法需要进行权限控

依赖注入(DI)有助于应用对象之间的解耦,而面向切面编程(AOP)有助于横切关注点与所影响的对象之间的解耦(转good)

依赖注入(DI)有助于应用对象之间的解耦,而面向切面编程(AOP)有助于横切关注点与所影响的对象之间的解耦.所谓横切关注点,即影响应用多处的功能,这些功能各个应用模块都需要,但又不是其主要关注点,常见的横切关注点有日志.事务和安全等. 将横切关注点抽离形成独立的类,即形成了切面.切面主要由切点和通知构成,通知定义了切面是什么,以及何时执行何种操作:切点定义了在何处执行通知定义的操作. http://ju.outofmemory.cn/entry/216839 引子: AOP(面向方面编程:Asp

利用基于@AspectJ的AOP实现权限控制

一. AOP与@AspectJ AOP 是 Aspect Oriented Programming 的缩写,意思是面向方面的编程.我们在系统开发中可以提取出很多共性的东西作为一个 Aspect,可以理解为在系统中,我们需要很多次重复实现的功能.比如计算某个方法运行了多少毫秒,判断用户是不是具有访问权限,用户是否已登录,数据的事务处理,日志记录等等. AOP的术语 连接点(Joinpoint) 程序执行的某个特殊位置:比如类开始初始化前,类初始化后,某个方法调用前,调用后等. 连接点 可 以 理解

Shiro学习(19)动态URL权限限制

用过Spring Security的朋友应该比较熟悉对URL进行全局的权限控制,即访问URL时进行权限匹配:如果没有权限直接跳到相应的错误页面.Shiro也支持类似的机制,不过需要稍微改造下来满足实际需求.不过在Shiro中,更多的是通过AOP进行分散的权限控制,即方法级别的:而通过URL进行权限控制是一种集中的权限控制.本章将介绍如何在Shiro中完成动态URL权限控制. 本章代码基于<第十六章 综合实例>,请先了解相关数据模型及基本流程后再学习本章. 表及数据SQL 请运行shiro-ex