• Shiro AuthorizingAnnotationMethodInterceptor权限注解方法拦截器


    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.
         *
         * 注入AuthorizingAnnotationHandler权限注解处理器提供给父类AnnotationMethodInterceptor
         */
        public AuthorizingAnnotationMethodInterceptor( AuthorizingAnnotationHandler handler ) {
            super(handler);
        }
    
        /**
         *
         * @param handler
         * @param resolver
         * @since 1.1
         *
         * 注入AuthorizingAnnotationHandler权限注解处理器和AnnotationResolver注解解析器提供给父类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.
         *
         * 调用核心方法assertAuthorized,执行目标方法
         */
        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.
         *
         * 获得AuthorizingAnnotationHandler权限注解处理器来处理判断是否有权限
         */
        public void assertAuthorized(MethodInvocation mi) throws AuthorizationException {
            try {
       // 由父类那获得自己曾经提供的权限注解处理器,执行处理工作,后文详解#1 ((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; } } }

    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
         *
         * 核心注解解析器,根据org.apache.shiro.aop.MethodInvocation提供的Method或Class信息和注解Class信息获得注解
         */
        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.
         *
         * 使用注解解析器获得注解,后文详解#2
         */
        protected Annotation getAnnotation(MethodInvocation mi) {
            return getResolver().getAnnotation(mi, getHandler().getAnnotationClass());
        }
    }

    MethodInterceptorSupport

    提供用户登入的信息和用户所拥有的权限信息,这样其子类则具备了登入会员的信息以判断会员是否具有权限

    /*
     * 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 org.apache.shiro.SecurityUtils;
    import org.apache.shiro.subject.Subject;
    
    
    /**
     * This class is an abstraction of AOP method interceptor behavior specific to Shiro that
     * leaves AOP implementation specifics to be handled by subclass implementations.  This implementation primarily
     * enables a <tt>Log</tt> and makes available the currently executing {@link Subject Subject}.
     *
     * @since 0.2
     */
    public abstract class MethodInterceptorSupport implements MethodInterceptor {
    
        /**
         * Default no-argument constructor for subclasses.
         */
        public MethodInterceptorSupport() {
        }
    
        /**
         * Returns the {@link Subject Subject} associated with the currently-executing code.
         * <p/>
         * This default implementation merely calls <code>{@link org.apache.shiro.SecurityUtils#getSubject SecurityUtils.getSubject()}</code>.
         *
         * @return the {@link org.apache.shiro.subject.Subject Subject} associated with the currently-executing code.
         */
        protected Subject getSubject() {
            return SecurityUtils.getSubject();
        }
    }

    RoleAnnotationMethodInterceptor

    /*
     * 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.AnnotationResolver;
    import org.apache.shiro.authz.annotation.RequiresRoles;
    
    
    /**
     * Checks to see if a @{@link RequiresRoles RequiresRoles} annotation is declared, and if so, performs
     * a role check to see if the calling <code>Subject</code> is allowed to invoke the method.
     *
     * @since 0.9
     */
    public class RoleAnnotationMethodInterceptor extends AuthorizingAnnotationMethodInterceptor {
    
        /**
         * Default no-argument constructor that ensures this interceptor looks for
         * {@link RequiresRoles RequiresRoles} annotations in a method declaration.
         *
         * 创建角色注解处理器提供给父类
         */
        public RoleAnnotationMethodInterceptor() {
            super( new RoleAnnotationHandler() );
        }
    
        /**
         * @param resolver
         * @since 1.1
         *
         * 注入注解解析器如SpringAnnotationResolver,创建角色注解处理器提供给父类
         */
        public RoleAnnotationMethodInterceptor(AnnotationResolver resolver) {
            super(new RoleAnnotationHandler(), resolver);
        }
    }

    书接前文#1

    getHandler()获得如RoleAnnotationHandler然后调用assertAuthorized(Annotation a)校验会员是否是某个角色

    RoleAnnotationHandler

    /*
     * 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.authz.AuthorizationException;
    import org.apache.shiro.authz.annotation.Logical;
    import org.apache.shiro.authz.annotation.RequiresRoles;
    
    import java.lang.annotation.Annotation;
    import java.util.Arrays;
    
    /**
     * Checks to see if a @{@link org.apache.shiro.authz.annotation.RequiresRoles RequiresRoles} annotation is declared, and if so, performs
     * a role check to see if the calling <code>Subject</code> is allowed to proceed.
     *
     * @since 0.9.0
     */
    public class RoleAnnotationHandler extends AuthorizingAnnotationHandler {
    
        /**
         * Default no-argument constructor that ensures this handler looks for
         * {@link org.apache.shiro.authz.annotation.RequiresRoles RequiresRoles} annotations.
         *
         * 提供RequiresRoles注解的Class信息给父类
         */
        public RoleAnnotationHandler() {
            super(RequiresRoles.class);
        }
    
        /**
         * Ensures that the calling <code>Subject</code> has the Annotation's specified roles, and if not, throws an
         * <code>AuthorizingException</code> indicating that access is denied.
         *
         * @param a the RequiresRoles annotation to use to check for one or more roles
         * @throws org.apache.shiro.authz.AuthorizationException
         *          if the calling <code>Subject</code> does not have the role(s) necessary to
         *          proceed.
         *
         * 核心校验,判断会员是否是某个角色
         */
        public void assertAuthorized(Annotation a) throws AuthorizationException {
            if (!(a instanceof RequiresRoles)) return;
    
            RequiresRoles rrAnnotation = (RequiresRoles) a;
            String[] roles = rrAnnotation.value();
    
            if (roles.length == 1) {
                // 使用Subject判断会员是否是某个角色,面向对象编程,会员自己拥有校验是否是某个角色的行为
                getSubject().checkRole(roles[0]);
                return;
            }
            if (Logical.AND.equals(rrAnnotation.logical())) {
                getSubject().checkRoles(Arrays.asList(roles));
                return;
            }
            if (Logical.OR.equals(rrAnnotation.logical())) {
                // Avoid processing exceptions unnecessarily - "delay" throwing the exception by calling hasRole first
                boolean hasAtLeastOneRole = false;
                for (String role : roles) if (getSubject().hasRole(role)) hasAtLeastOneRole = true;
                // Cause the exception if none of the role match, note that the exception message will be a bit misleading
                if (!hasAtLeastOneRole) getSubject().checkRole(roles[0]);
            }
        }
    
    }

    书接前文#2

    getResolver()获得SpringAnnotationResolver,然后调用getAnnotation(MethodInvocation mi, Annotation a)获得注解信息

    SpringAnnotationResolver

    /*
     * 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.aop;
    
    import org.apache.shiro.aop.AnnotationResolver;
    import org.apache.shiro.aop.MethodInvocation;
    import org.springframework.core.annotation.AnnotationUtils;
    import org.springframework.util.ClassUtils;
    
    import java.lang.annotation.Annotation;
    import java.lang.reflect.Method;
    
    /**
     * {@code AnnotationResolver} implementation that uses Spring's more robust
     * {@link AnnotationUtils AnnotationUtils} to find method annotations instead of the JDKs simpler
     * (and rather lacking) {@link Method}.{@link Method#getAnnotation(Class) getAnnotation(class)}
     * implementation.
     *
     * @since 1.1
     */
    public class SpringAnnotationResolver implements AnnotationResolver {
    
        public Annotation getAnnotation(MethodInvocation mi, Class<? extends Annotation> clazz) {
            Method m = mi.getMethod();
    
            Annotation a = AnnotationUtils.findAnnotation(m, clazz);
            if (a != null) return a;
    
            //The MethodInvocation's method object could be a method defined in an interface.
            //However, if the annotation existed in the interface's implementation (and not
            //the interface itself), it won't be on the above method object.  Instead, we need to
            //acquire the method representation from the targetClass and check directly on the
            //implementation itself:
            Class<?> targetClass = mi.getThis().getClass();
            m = ClassUtils.getMostSpecificMethod(m, targetClass);
            a = AnnotationUtils.findAnnotation(m, clazz);
            if (a != null) return a;
            // See if the class has the same annotation
            return AnnotationUtils.findAnnotation(mi.getThis().getClass(), clazz);
        }
    }
  • 相关阅读:
    B端产品经理的价值
    APP场景流程分析
    大众点评
    降低成本
    抽象不变的,可变的
    优惠券统计报表
    JSON WEB TOKEN
    vue开发项目的坑-[Vue warn]: Do not use built-in or reserved HTML elements as component id: MenuItem
    redis分布式锁和消息队列
    thinkphp 面向切面编程-行为拓展
  • 原文地址:https://www.cnblogs.com/BINGJJFLY/p/9071138.html
Copyright © 2020-2023  润新知