自定義權限註解

一、Shiro權限原理:spring-shiro.xml須要配置java

<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">spring

</bean>這個bean,用來匹配他本身定義的權限註解express

/*apache

 * Licensed to the Apache Software Foundation (ASF) under oneapp

 * or more contributor license agreements.  See the NOTICE fileless

 * distributed with this work for additional informationide

 * regarding copyright ownership.  The ASF licenses this fileui

 * to you under the Apache License, Version 2.0 (thethis

 * "License"); you may not use this file except in compliancespa

 * 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 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());

                if ( isAuthzAnnotationPresent(m) ) {

                    return true;

                }

            } 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(Method method) {

        for( Class<? extends Annotation> annClass : AUTHZ_ANNOTATION_CLASSES ) {

            Annotation a = AnnotationUtils.findAnnotation(method, annClass);

            if ( a != null ) {

                return true;

            }

        }

        return false;

    }

 

}

此類繼承StaticMethodMatcherPointcutAdvisor父類, AUTHZ_ANNOTATION_CLASSES 是他本身定義的註解類集合,matches方法匹配訪問方法是否有他本身定義的註解。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 {

 

    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));

 

        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.

     */

    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>.

     */

    public Object invoke(MethodInvocation methodInvocation) throws Throwable {

        org.apache.shiro.aop.MethodInvocation mi = createMethodInvocation(methodInvocation);

        return super.invoke(mi);

    }

}

 

這個類是申明的AopAllianceAnnotationsAuthorizingMethodInterceptor攔截器的集合,須要注意的是他的每個攔截器 如RoleAnnotationMethodInterceptor:主要由一個XXHandler(匹配註解值和用戶權限)和AnnotationResolver(獲取註解對象)構成。

 

 

二、仿寫:bean類繼承org.springframework.aop.support.StaticMethodMatcherPointcutAdviso

r這個類,經過實現match方法匹配切點實例所示

public class AuthorizationAdvisor extends StaticMethodMatcherPointcutAdvisor{

/**

 * @Fields serialVersionUID : TODO

 */

private static final long serialVersionUID = -880533033433547002L;

 

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

 

    @SuppressWarnings("unchecked")

private static final Class<? extends Annotation>[] AUTHZ_ANNOTATION_CLASSES =

            new Class[] {RequiresResource.class};

 

    

    /**

     * Create a new AuthorizationAttributeSourceAdvisor.

     */

    public AuthorizationAdvisor() {

        setAdvice(new AnnotationsMethodInterceptor());

    }

    

    /**

     * Returns <tt>true</tt> if the method 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());

                if ( isAuthzAnnotationPresent(m) ) {

                    return true;

                }

            } catch (NoSuchMethodException ignored) {

             log.error("targetClass is null");

                //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(Method method) {

        for( Class<? extends Annotation> annClass : AUTHZ_ANNOTATION_CLASSES ) {

            Annotation a = AnnotationUtils.findAnnotation(methodannClass);

            if ( a != null ) {

                return true;

            }

        }

        return false;

}

 

 

RequiresResource這個是自定義的註解類;matches匹配方法註解假如返回true,就會進入攔截器AnnotationsMethodInterceptor攔截器方法以下

public class AnnotationsMethodInterceptor extends MethodInterceptorSupport implements MethodInterceptor {

 

protected Collection<AuthorizingAnnotationMethodInterceptor> methodInterceptors;

 

public AnnotationsMethodInterceptor() {

List<AuthorizingAnnotationMethodInterceptor> interceptors = new ArrayList<AuthorizingAnnotationMethodInterceptor>(

5);

 

AnnotationResolver resolver = new SpringAnnotationResolver();

 

interceptors.add(new RequiresResourceMethodInterceptor(resolver));

 

setMethodInterceptors(interceptors);

}

 

/**

 * 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()

 */

public void setMethodInterceptors(Collection<AuthorizingAnnotationMethodInterceptor> methodInterceptors) {

this.methodInterceptors = methodInterceptors;

}

 

/**

 * 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.

 */

protected MethodInvocation createMethodInvocation(Object implSpecificMethodInvocation) {

final org.aopalliance.intercept.MethodInvocation mi = (org.aopalliance.intercept.MethodInvocation) implSpecificMethodInvocation;

 

return new 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 aopAllianceMethodInvocationthrows Throwable {

MethodInvocation mi = (MethodInvocation) aopAllianceMethodInvocation;

return mi.proceed();

}

 

/*

 * (non-Javadoc) 獲取對應的註解並解析

 */

protected boolean assertAuthorized(MethodInvocation methodInvocationthrows AuthorizationException {

// default implementation just ensures no deny votes are cast:

boolean b = true;

Collection<AuthorizingAnnotationMethodInterceptor> aamis = getMethodInterceptors();

if (aamis != null && !aamis.isEmpty()) {

for (AuthorizingAnnotationMethodInterceptor aami : aamis) {

if (aami.supports(methodInvocation)) {

b = aami.assertAuthorized(methodInvocation);

}

}

}

return b;

}

 

@Override

public Object invoke(org.aopalliance.intercept.MethodInvocation invocationthrows Throwable {

MethodInvocation mi = createMethodInvocation(invocation);

if (assertAuthorized(mi)) {

return mi.proceed();

else {

return null;

}

}

 

}

大部分代碼來源shiro,這裏不詳細說明了就,須要注意的是紅色區域內,假如爲true,方法正常往下走(客戶端訪問的方法),假如爲false,不往下進行,什麼也不返回。

相關文章
相關標籤/搜索