spring security总结 太有用了!!

转至:  http://www.cnblogs.com/yl2755/archive/2012/04/19/2456823.html
谢谢作者!!!

首先导入spring security所需要的jar包 
spring-security-core-2.0.5.RELEASE.jar 
spring-security-core-tiger-2.0.5.RELEASE.jar 
一.配置过滤器 
在web.xml中定义如下过滤器 
   
        springSecurityFilterChain 
        org.springframework.web.filter.DelegatingFilterProxy 
     
     
        springSecurityFilterChain 
         
CREATE TABLE `t_account` ( 
  `id` int(11) NOT NULL, 
  `username` varchar(255) default NULL, 
  `password` varchar(255) default NULL, 
  `enabled` int default NULL,  
  PRIMARY KEY  (`id`) 
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 
     
    CREATE TABLE `t_role` ( 
  `id` int(11) NOT NULL, 
  `name` varchar(255) default NULL,  
  `descn` varchar(255) default NULL,  
  PRIMARY KEY  (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

 
CREATE TABLE `t_account_role` ( 
  `a_id` int(11) NOT NULL, 
  `r_id` int(11) NOT NULL, 
  PRIMARY KEY  (`a_id`,`r_id`), 
  KEY `FK1C2BC9332D31C656` (`r_id`), 
  KEY `FK1C2BC93371CCC630` (`a_id`), 
  CONSTRAINT `FK1C2BC93384B0A30E` FOREIGN KEY (`a_id`) REFERENCES `t_account` (`id`), 
  CONSTRAINT `FK1C2BC9332D31C656` FOREIGN KEY (`r_id`) REFERENCES `t_role` (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

 
insert into t_account values(1,'zhangsan','123',1); 
insert into t_account values(2,'lisi','321',1); 

insert into t_role values(1,'系统管理员','ROLE_ADMIN'); 
insert into t_role values(2,'普通用户','ROLE_USER'); 

insert into t_account_role values(1,2); 
    insert into t_account_role values(2,1); 
    
当用户登录时,spring security首先判断用户是否可以登录。用户登录后spring security获得该用户的 
所有权限以判断用户是否可以访问资源。 

spring配置文件中定义 
 
       
        users-by-username-query="select username,password,enabled from t_account where username=?" 
        authorities-by-username-query="select r.descn from t_account_role ar join 
         t_account a on ar.a_id=a.id join t_role r on ar.r_id=r.id where a.username=?"/> 
     
    
    users-by-username-query:根据用户名查找用户 
    authorities-by-username-query:根据用户名查找这个用户所有的角色名,将用户访问的URL地址和 
    查询结果与标签进行匹配。 
    匹配成功就允许访问,否则就返回到提示页面。 

    
    在标签中添加登录页面等信息 
     
       
         
        CREATE TABLE `t_account` ( 
  `id` int(11) NOT NULL, 
  `username` varchar(255) default NULL, 
  `password` varchar(255) default NULL, 
  `enabled` int default NULL,  
  PRIMARY KEY  (`id`) 
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 
     
    CREATE TABLE `t_role` ( 
  `id` int(11) NOT NULL, 
  `name` varchar(255) default NULL,  
  `descn` varchar(255) default NULL,  
  PRIMARY KEY  (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

 
CREATE TABLE `t_account_role` ( 
  `a_id` int(11) NOT NULL, 
  `r_id` int(11) NOT NULL, 
  PRIMARY KEY  (`a_id`,`r_id`), 
  KEY `FK1C2BC9332D31C656` (`r_id`), 
  KEY `FK1C2BC93371CCC630` (`a_id`), 
  CONSTRAINT `FK1C2BC93384B0A30E` FOREIGN KEY (`a_id`) REFERENCES `t_account` (`id`), 
  CONSTRAINT `FK1C2BC9332D31C656` FOREIGN KEY (`r_id`) REFERENCES `t_role` (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 
 
CREATE TABLE `t_module` ( 
  `id` int(11) NOT NULL, 
  `name` varchar(255) default NULL, 
  `address` varchar(255) default NULL, 
  PRIMARY KEY  (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

 
CREATE TABLE `t_module_role` ( 
  `m_id` int(11) NOT NULL, 
  `r_id` int(11) NOT NULL, 
  PRIMARY KEY  (`m_id`,`r_id`), 
  KEY `FKA713071E2D31C656` (`r_id`), 
  KEY `FKA713071ED78C9071` (`m_id`), 
  CONSTRAINT `FKA713071ED78C9071` FOREIGN KEY (`m_id`) REFERENCES `t_module` (`id`), 
  CONSTRAINT `FKA713071E2D31C656` FOREIGN KEY (`r_id`) REFERENCES `t_role` (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

 
insert into t_account values(1,'zhangsan','123',1); 
insert into t_account values(2,'lisi','321',1); 

insert into t_role values(1,'系统管理员','ROLE_ADMIN'); 
insert into t_role values(2,'普通用户','ROLE_USER'); 

insert into t_account_role values(1,2); 
    insert into t_account_role values(2,1); 
    
    insert into t_module values(1,'部门管理','/dept.jsp'); 
    insert into t_module values(2,'人员管理','/emp.jsp'); 
    
    insert into `t_module_role` values(1,1); 
    insert into `t_module_role` values(1,2); 
    insert into `t_module_role` values(2,1); 
    
1.在自定义的过滤器中获取资源的URL地址和角色名以取代spring配置文件中原有的 
    过滤器代码: 
import java.sql.ResultSet; 
import java.sql.SQLException; 

import java.util.LinkedHashMap; 
import java.util.List; 
import java.util.Map; 

import javax.sql.DataSource; 

import org.springframework.beans.factory.FactoryBean; 

import org.springframework.jdbc.core.support.JdbcDaoSupport; 
import org.springframework.jdbc.object.MappingSqlQuery; 

import org.springframework.security.ConfigAttributeDefinition; 
import org.springframework.security.ConfigAttributeEditor; 
import org.springframework.security.intercept.web.DefaultFilterInvocationDefinitionSource; 
import org.springframework.security.intercept.web.FilterInvocationDefinitionSource; 
import org.springframework.security.intercept.web.RequestKey; 
import org.springframework.security.util.AntUrlPathMatcher; 
import org.springframework.security.util.UrlMatcher; 


public class JdbcFilterInvocationDefinitionSourceFactoryBean 
    extends JdbcDaoSupport implements FactoryBean { 
    private String resourceQuery; 

    public boolean isSingleton() { 
        return true; 
    } 

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

    public Object getObject() { 
        return new DefaultFilterInvocationDefinitionSource(this 
            .getUrlMatcher(), this.buildRequestMap()); 
    } 

    protected Map findResources() { 
        ResourceMapping resourceMapping = new ResourceMapping(getDataSource(), 
                resourceQuery); 

        Map resourceMap = new LinkedHashMap(); 

        for (Resource resource : (List) resourceMapping.execute()) { 
            String url = resource.getUrl(); 
            String role = resource.getRole(); 

            if (resourceMap.containsKey(url)) { 
                String value = resourceMap.get(url); 
                resourceMap.put(url, value + "," + role); 
            } else { 
                resourceMap.put(url, role); 
            } 
        } 

        return resourceMap; 
    } 

    protected LinkedHashMap buildRequestMap() { 
        LinkedHashMap requestMap = null; 
        requestMap = new LinkedHashMap(); 

        ConfigAttributeEditor editor = new ConfigAttributeEditor(); 

        Map resourceMap = this.findResources(); 

        for (Map.Entry entry : resourceMap.entrySet()) { 
            RequestKey key = new RequestKey(entry.getKey(), null); 
            editor.setAsText(entry.getValue()); 
            requestMap.put(key, 
                (ConfigAttributeDefinition) editor.getValue()); 
        } 

        return requestMap; 
    } 

    protected UrlMatcher getUrlMatcher() { 
        return new AntUrlPathMatcher(); 
    } 

    public void setResourceQuery(String resourceQuery) { 
        this.resourceQuery = resourceQuery; 
    } 

    private class Resource { 
        private String url; 
        private String role; 

        public Resource(String url, String role) { 
            this.url = url; 
            this.role = role; 
        } 

        public String getUrl() { 
            return url; 
        } 

        public String getRole() { 
            return role; 
        } 
    } 

    private class ResourceMapping extends MappingSqlQuery { 
        protected ResourceMapping(DataSource dataSource, 
            String resourceQuery) { 
            super(dataSource, resourceQuery); 
            compile(); 
        } 

        protected Object mapRow(ResultSet rs, int rownum) 
            throws SQLException { 
            String url = rs.getString(1); 
            String role = rs.getString(2); 
            Resource resource = new Resource(url, role); 
            
            return resource; 
        } 
    } 


将自定义的过滤器放入到原有的spring security过滤器链中(在spring配置文件中配置) 
定义自定义过滤器(sql语句用于查询资源的URL地址 如:/index.jsp 和角色名 如ROLE_USER) 

        class="com.lovo.JdbcFilterInvocationDefinitionSourceFactoryBean"> 
         
                    select m.address,r.descn 
from t_module_role mr 
join t_module m on mr.m_id=m.id 
join t_role r on mr.r_id=r.id; 
        "/> 
     
  将自定义过滤器放入过滤器链中 
 
        class="org.springframework.security.intercept.web.FilterSecurityInterceptor" > 
         
         
     
    注意:FilterSecurityInterceptor过滤器会向request中写入一个标记,用于标记是否已经控制了当前请求,以避免对同一请求多次处理,导致第2个FilterSecurityInterceptor不会再次执行。 
    在中不需要再定义,如下: 
     
       
                    authentication-failure-url="/error.jsp" 
                    default-target-url="/index.jsp" /> 
                    
     
    自定义的过滤器就从配置文件中读取sql,查询结果就是角色和资源,用户登录时就在session中保存了用户的角色。 
    注意:intercept-url的先后顺序,spring security使用第一个能匹配的intercept-url标签进行权限控制。 
    现在intercept-url来源于数据库,所以在sql查询时注意角色和资源的顺序。 
    建议在角色和资源的中间表中添加1个字段用于标识顺序,(按从严到宽的顺序) 
    表结构修改如下: 
     
CREATE TABLE `t_module_role` ( 
  `m_id` int(11) NOT NULL, 
  `r_id` int(11) NOT NULL, 
  `priority` int(11) default NULL,  
  PRIMARY KEY  (`m_id`,`r_id`), 
  KEY `FKA713071E2D31C656` (`r_id`), 
  KEY `FKA713071ED78C9071` (`m_id`), 
  CONSTRAINT `FKA713071ED78C9071` FOREIGN KEY (`m_id`) REFERENCES `t_module` (`id`), 
  CONSTRAINT `FKA713071E2D31C656` FOREIGN KEY (`r_id`) REFERENCES `t_role` (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

数据如下: 
insert into t_account values(1,'zhangsan','123',1); 
insert into t_account values(2,'lisi','321',1); 

insert into t_role values(1,'系统管理员','ROLE_ADMIN'); 
insert into t_role values(2,'普通用户','ROLE_USER'); 

insert into t_account_role values(1,2); 
    insert into t_account_role values(2,1); 
    
    insert into t_module values(1,'部门管理','/dept.jsp'); 
    insert into t_module values(2,'人员管理','/emp.jsp'); 
    
    insert into `t_module_role` values(1,1,3); 
    insert into `t_module_role` values(1,2,2); 
    insert into `t_module_role` values(2,1,1); 
    
    自定义过滤器修改如下: 
   
        class="com.lovo.JdbcFilterInvocationDefinitionSourceFactoryBean"> 
         
                    select m.address,r.descn 
from t_module_role mr 
join t_module m on mr.m_id=m.id 
join t_role r on mr.r_id=r.id 
order by mr.priority 
        "/> 
     
    
    如果持久层使用的是hibernate,那么只需要给自定义过滤器注入1个hibernateTemplate. 
    在自定义过滤器中就不需要再使用mapRow的方式。而是直接获取url和角色名即可。 
    例如: 
    public class ModuleFilter implements FactoryBean { 
private String resourceQuery; 

    public boolean isSingleton() { 
        return true; 
    } 

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

    public Object getObject() { 
        return new DefaultFilterInvocationDefinitionSource(this 
            .getUrlMatcher(), this.buildRequestMap()); 
    } 

    protected Map findResources() { 
        ResourceMapping resourceMapping = new ResourceMapping(); 

        Map resourceMap = new LinkedHashMap(); 

        for (Resource resource : (List) resourceMapping.execute()) { 
            String url = resource.getUrl(); 
            String role = resource.getRole(); 

            if (resourceMap.containsKey(url)) { 
                String value = resourceMap.get(url); 
                resourceMap.put(url, value + "," + role); 
            } else { 
                resourceMap.put(url, role); 
            } 
        } 

        return resourceMap; 
    } 

    protected LinkedHashMap buildRequestMap() { 
        LinkedHashMap requestMap = null; 
        requestMap = new LinkedHashMap(); 

        ConfigAttributeEditor editor = new ConfigAttributeEditor(); 

        Map resourceMap = this.findResources(); 

        for (Map.Entry entry : resourceMap.entrySet()) { 
            RequestKey key = new RequestKey(entry.getKey(), null); 
            editor.setAsText(entry.getValue()); 
            requestMap.put(key, 
                (ConfigAttributeDefinition) editor.getValue()); 
        } 

        return requestMap; 
    } 

    protected UrlMatcher getUrlMatcher() { 
        return new AntUrlPathMatcher(); 
    } 

    public void setResourceQuery(String resourceQuery) { 
        this.resourceQuery = resourceQuery; 
    } 

    private class Resource { 
        private String url; 
        private String role; 

        public Resource(String url, String role) { 
            this.url = url; 
            this.role = role; 
        } 

        public String getUrl() { 
            return url; 
        } 

        public String getRole() { 
            return role; 
        } 
    } 

    private class ResourceMapping{ 
        public List execute(){ 
        List rlist = new ArrayList(); 
        List list = hibernateTemplate.find(resourceQuery); 
        for(int i=0;i
        Role role = list.get(i); 
        Set set = role.getModuleSet(); 
        Iterator it = set.iterator(); 
        while(it.hasNext()){ 
        Module m = it.next(); 
        Resource re = new Resource(m.getUrl(),role.getDescn()); 
        rlist.add(re); 
        } 
        } 
return rlist; 
        } 
    } 

    public void setHibernateTemplate(HibernateTemplate hibernateTemplate) { 
this.hibernateTemplate = hibernateTemplate; 


private HibernateTemplate hibernateTemplate; 

而从灵活性的角度考虑,把hql写在配置文件中 
 
        
         value="from com.lovo.po.Role order by ind"> 
          
          
          
     
    
    问题:系统只会在初始化的时候从数据库中加载信息。无法识别数据库中信息的改变。 
    解决:每个jsp页面上重新内存 
    代码:每个jsp页面include如下代码: 

版权声明:本文为博主原创文章,未经博主允许不得转载。

转载于:https://www.cnblogs.com/ubuntuvim/p/4796542.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值