spring security 2.0 的简单配置使用(补)——用aop控制method级权限

上次写了spring security 2.0 的简单配置使用 ,这里再做一下补充。

method级别的权限控制可以通过spring aop来实现。

pointcut:

    <aop:config>
        <aop:pointcut id="securityPointcut"
            expression="execution(** org.catspaw.ss2test1.service.*Service+.*(..))" />
        <aop:advisor advice-ref="accessDeniedInterceptor"
            pointcut-ref="securityPointcut" order="0" />
        <aop:advisor advice-ref="methodSecurityInterceptor"
            pointcut-ref="securityPointcut" order="1" />
    </aop:config>

当调用org.catspaw.ss2test1.service包下所有Service结尾的类的任何方法时,通知accessDeniedInterceptor和methodSecurityInterceptor两个Interceptor。

 

MethodSecurityInterceptor,作用和FilterSecurityInterceptor差不多,如果授权不通过,也会抛异常。

    <bean id="methodSecurityInterceptor"
        class="org.springframework.security.intercept.method.aopalliance.MethodSecurityInterceptor">
        <property name="authenticationManager" ref="authenticationManager" />
        <property name="accessDecisionManager" ref="accessDecisionManager" />
        <property name="objectDefinitionSource"
            ref="databaseMethodDefinitionSource" />
    </bean>

 DefaultMethodDefinitionSource,作用类似于DefaultFilterInvocationDefinitionSource

    <bean id="databaseMethodDefinitionSource"
        class="org.catspaw.ss2test1.security.DefaultMethodDefinitionSource">
        <constructor-arg index="0">
            <bean
                class="org.catspaw.ss2test1.security.SimpleAspectJMethodMatcher" />
        </constructor-arg>
        <constructor-arg index="1">
            <bean class="org.catspaw.ss2test1.security.MethodMapFactoryBean">
                <property name="resourceDao" ref="resourceDao" />
            </bean>
        </constructor-arg>
    </bean>

 实现:

package org.catspaw.ss2test1.security;

import org.springframework.security.ConfigAttributeDefinition;
import org.springframework.security.intercept.method.AbstractFallbackMethodDefinitionSource;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

/**
 * 从数据库获取被访问的资源所需要的权限标识符
 * 这里只处理Method(方法)资源
 * 
 * @author 孙宁振
 */
public class DefaultMethodDefinitionSource extends
        AbstractFallbackMethodDefinitionSource {

    private Matcher<String, Method>                          methodMatcher;
    private LinkedHashMap<String, ConfigAttributeDefinition> methodMap = new LinkedHashMap<String, ConfigAttributeDefinition>();

    public DefaultMethodDefinitionSource(Matcher<String, Method> methodMatcher,
            LinkedHashMap<String, ConfigAttributeDefinition> methodMap) {
        this.methodMatcher = methodMatcher;
        this.methodMap = methodMap;
    }

    public Collection getConfigAttributeDefinitions() {
        return Collections.unmodifiableCollection(getMethodMap().values());
    }

    @Override
    protected ConfigAttributeDefinition findAttributes(Method method,
            Class targetClass) {
        Set<Entry<String, ConfigAttributeDefinition>> set = getMethodMap()
                .entrySet();
        for (Entry<String, ConfigAttributeDefinition> entry : set) {
            String pattern = entry.getKey();
            boolean matched = getMethodMatcher().match(pattern, method);
            if (matched) {
                return entry.getValue();
            }
        }
        return null;
    }

    @Override
    protected ConfigAttributeDefinition findAttributes(Class clazz) {
        return null;
    }

    public Map<String, ConfigAttributeDefinition> getMethodMap() {
        return methodMap;
    }

    public Matcher<String, Method> getMethodMatcher() {
        return methodMatcher;
    }
}

 

SimpleAspectJMethodMatcher ,Matcher接口省略

package org.catspaw.ss2test1.security;

import java.lang.reflect.Method;
import org.aspectj.weaver.tools.PointcutExpression;
import org.aspectj.weaver.tools.PointcutParser;
import org.aspectj.weaver.tools.ShadowMatch;

/**
 * Method匹配器实现
 * 用AspectJ PointCut表达式匹配目标方法
 * 
 * @author 孙宁振
 */
public class SimpleAspectJMethodMatcher implements Matcher<String, Method> {

    private PointcutParser pointcutParser = PointcutParser
                                                  .getPointcutParserSupportingAllPrimitivesAndUsingContextClassloaderForResolution();

    public boolean match(String pattern, Method method) {
        pattern = "execution(" + pattern + ")";
        PointcutExpression pe = pointcutParser.parsePointcutExpression(pattern);
        ShadowMatch match = pe.matchesMethodExecution(method);
        return match.alwaysMatches();
    }

    public void setPointcutParser(PointcutParser pointcutParser) {
        this.pointcutParser = pointcutParser;
    }

    public PointcutParser getPointcutParser() {
        return pointcutParser;
    }
}

 

 MethodMapFactoryBean ,作用类似于RequestMapFactoryBean:

package org.catspaw.ss2test1.security;

import java.util.LinkedHashMap;
import java.util.List;
import org.catspaw.ss2test1.dao.ResourceDao;
import org.catspaw.ss2test1.model.Resource;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.security.ConfigAttributeDefinition;

public class MethodMapFactoryBean implements FactoryBean {

    private static final String                              RESOURCE_TYPE = "METHOD";
    private ResourceDao                                      resourceDao;
    private LinkedHashMap<String, ConfigAttributeDefinition> methodMap;

    public void init() {
        List<Resource> resources = resourceDao.find(RESOURCE_TYPE);
        methodMap = new LinkedHashMap<String, ConfigAttributeDefinition>();
        for (Resource resource : resources) {
            ConfigAttributeDefinition definition = new ConfigAttributeDefinition(
                    resource.getAuthority());
            methodMap.put(resource.getResourceString(), definition);
        }
    }

    public Object getObject() throws Exception {
        if (methodMap == null) {
            init();
        }
        return methodMap;
    }

    public Class getObjectType() {
        return LinkedHashMap.class;
    }

    public boolean isSingleton() {
        return true;
    }

    public ResourceDao getResourceDao() {
        return resourceDao;
    }

    public void setResourceDao(ResourceDao resourceDao) {
        this.resourceDao = resourceDao;
    }
}

 

另外,AccessDeniedInterceptor 的作用是在授权失败,抛出异常后,做一些其他的处理工作,需要实现ThrowsAdvice 接口。比如:

package org.catspaw.ss2test1.security;

import java.lang.reflect.Method;
import org.springframework.aop.ThrowsAdvice;
import org.springframework.security.AccessDeniedException;

/**
 * 控制权限的AOP拦截器抛出AccessDeniedException后,进行相应后续处理
 * 
 * @author 孙宁振
 *
 */
public class AccessDeniedInterceptor implements ThrowsAdvice {

    public void afterThrowing(Method method, Object[] args, Object target,
            AccessDeniedException exception) {
        System.out.println("access denied.....");
        //TODO 通过DatabaseMethodDefinitionSource拒绝访问后的处理
    }
}

 注意:accessDeniedInterceptor的order需要在methodSecurityInterceptor的order之前,否则methodSecurityInterceptor抛出异常后,accessDeniedInterceptor将不会执行。

 

HelloService

    <bean id="helloService"
        class="org.catspaw.ss2test1.service.impl.HelloServiceImpl">
    </bean>

 接口:

package org.catspaw.ss2test1.service;

public interface HelloService {

    void hello();

    void hello(String name);
}

 

实现:

package org.catspaw.ss2test1.service.impl;

import org.catspaw.ss2test1.service.HelloService;

public class HelloServiceImpl implements HelloService {

    public void hello() {
        System.out.println("hello.......");
    }

    public void hello(String name) {
        System.out.println("hello " + name);
    }
}

 测试用的Servlet

package org.catspaw.ss2test1.servlet;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.catspaw.ss2test1.service.HelloService;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

public class HelloServlet extends HttpServlet {

    private HelloService helloService;

    @Override
    public void init() throws ServletException {
        super.init();
        ApplicationContext ctx = WebApplicationContextUtils
                .getRequiredWebApplicationContext(getServletContext());
        helloService = (HelloService) ctx.getBean("helloService");
    }

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        String name = request.getParameter("name");
        if (name != null) {
            helloService.hello(name);
        } else {
            helloService.hello();
        }
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }
}

 

附demo
所用到的jar:spring2.0.7,hibernate3.2.5&jpa,spring-security2.0.3,ehcache1.3

数据库:mysql5,建好相应数据库后,把<prop key="hibernate.hbm2ddl.auto">none</prop>的none改为create即可在运行时自动建表
登录入口为/spring_security_login

用户名   密码
admin    admin
aaa      aaa
bbb      bbb

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值