
spring security使用数据库资源
国内对权限系统的基本要求是将用户权限和被保护资源都放在数据库里进行管理,在这点上Spring Security并没有给出官方的解决方案,为此我们需要对Spring Security进行扩展。、数据库表结构这次我们使用五张表,user用户表,role角色表,resc资源表相互独立,它们通过各自之间的连接表实现多对多关系。我们自己定义的表结构。-- 资源create table resc(id bigint,name varchar(50),res_type varchar(50),res_string varchar(200),priority integer,descn varchar(200));alter table resc add constraint pk_resc primary key(id);alter table resc alter column id bigint generated by default as identity(start with 1);-- 角色create table role(id bigint,name varchar(50),descn varchar(200));alter table role add constraint pk_role primary key(id);alter table role alter column id bigint generated by default as identity(start with 1);-- 用户create table user(id bigint,username varchar(50),password varchar(50),status integer,descn varchar(200));alter table user add constraint pk_user primary key(id);alter table user alter column id bigint generated by default as identity(start with 1);-- 资源角色连接表create table resc_role(resc_id bigint,role_id bigint);alter table resc_role add constraint pk_resc_role primary key(resc_id, role_id);alter table resc_role add constraint fk_resc_role_resc foreign key(resc_id) references resc(id);alter table resc_role add constraint fk_resc_role_role foreign key(role_id) references role(id);-- 用户角色连接表create table user_role(user_id bigint,role_id bigint);alter table user_role add constraint pk_user_role primary key(user_id, role_id);alter table user_role add constraint fk_user_role_user foreign key(user_id) references user(id);alter table user_role add constraint fk_user_role_role foreign key(role_id) references role(id);ER图如下表示图 5.1. 数据库表关系我们在已有表结构中插入一些数据。insert into user(id,username,password,status,descn) values(1,'admin','admin',1,'管理员');insert into user(id,username,password,status,descn) values(2,'user','user',1,'用户');insert into role(id,name,descn) values(1,'ROLE_ADMIN','管理员角色');insert into role(id,name,descn) values(2,'ROLE_USER','用户角色');insert into resc(id,name,res_type,res_string,priority,descn) values(1,'','URL','/admin.jsp',1,'');insert into resc(id,name,res_type,res_string,priority,descn) values(2,'','URL','/**',2,'');insert into resc_role(resc_id,role_id) values(1,1);insert into resc_role(resc_id,role_id) values(2,1);insert into resc_role(resc_id,role_id) values(2,2);insert into user_role(user_id,role_id) values(1,1);insert into user_role(user_id,role_id) values(1,2);insert into user_role(user_id,role_id) values(2,2);Spring Security没有提供从数据库获得获取资源信息的方法,实际上Spring Security甚至没有为我们留一个半个的扩展接口,所以我们这次要费点儿脑筋了。首先,要搞清楚需要提供何种类型的数据,然后,寻找可以让我们编写的代码替换原有功能的切入点,实现了以上两步之后,就可以宣布大功告成了。1.从配置文件上可以看到,Spring Security所需的数据应该是一系列URL网址和访问这些网址所需的权限:<intercept-url pattern="/login.jsp" access="IS_AUTHENTICATED_ANONYMOUSLY" /><intercept-url pattern="/admin.jsp" access="ROLE_ADMIN" /><intercept-url pattern="/**" access="ROLE_USER" />select re.res_string,r.namefrom role rjoin resc_role rron r.id=rr.role_idjoin resc reon re.id=rr.resc_idorder by re.priority完整代码package com.family168.springsecuritybook.ch005;import java.sql.ResultSet;import java.sql.SQLException;import java.util.Collection;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.access.ConfigAttribute;import org.springframework.security.access.ConfigAttributeEditor;import org.springframework.security.web.access.intercept.DefaultFilterInvocationSecurityMetadataSource;import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;import org.springframework.security.web.access.intercept.RequestKey;import org.springframework.security.web.util.AntPathRequestMatcher;import org.springframework.security.web.util.RequestMatcher;public class JdbcFilterInvocationDefinitionSourceFactoryBeanextends JdbcDaoSupport implements FactoryBean {private String resourceQuery;public boolean isSingleton() {return true;}public Class getObjectType() {return FilterInvocationSecurityMetadataSource.class;}public Object getObject() {return new DefaultFilterInvocationSecurityMetadataSource(this.buildRequestMap());}protected Map<String, String> findResources() {ResourceMapping resourceMapping = new ResourceMapping(getDataSource(),resourceQuery);Map<String, String> resourceMap = new LinkedHashMap<String, String>();for (Resource resource : (List<Resource>) 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<RequestMatcher, Collection<ConfigAttribute>> buildRequestMap() {LinkedHashMap<RequestMatcher, Collection<ConfigAtt