最近一直在学习spring security3,试着搭建了环境:
项目配置pom.xml文件
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.github.humeng126</groupId> <artifactId>security-07</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <name>security-07</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <springsecurity.version>3.2.3.RELEASE</springsecurity.version> <spring.version>4.0.3.RELEASE</spring.version> <mysql-connector.version>5.1.30</mysql-connector.version> </properties> <dependencies> <!-- web begin --> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> <scope>provided</scope> </dependency> <!-- web end --> <!-- spring begin --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.6.9</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.6.9</version> </dependency> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>2.2.2</version> </dependency> <dependency> <groupId>asm</groupId> <artifactId>asm</artifactId> <version>3.3.1</version> </dependency> <!-- spring end --> <!-- security begin --> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-core</artifactId> <version>${springsecurity.version}</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-taglibs</artifactId> <version>${springsecurity.version}</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>${springsecurity.version}</version> </dependency> <!-- security end --> <!-- pool begin --> <dependency> <groupId>commons-dbcp</groupId> <artifactId>commons-dbcp</artifactId> <version>1.4</version> </dependency> <!-- pool end --> <!-- connector begin --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql-connector.version}</version> </dependency> <!-- connector end --> <!-- test begin --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> </dependency> <!-- test end --> <!-- cache begin --> <dependency> <groupId>net.sf.ehcache</groupId> <artifactId>ehcache-core</artifactId> <version>2.6.9</version> </dependency> <!-- cache end --> </dependencies> </project>
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> <display-name>security-01</display-name> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext*.xml</param-value> </context-param> <filter> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> </web-app>
<?xml version="1.0" encoding="UTF-8"?> <!-- 声明在xml中使用Spring Security提供的命名空间 --> <b:beans xmlns="http://www.springframework.org/schema/security" xmlns:b="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd"> <!-- 注意这个custom-filter标签,它表示将filterSecurityInterceptor放在框架原来的FILTER_SECURITY_INTERCEPTOR过滤器之前, 这样我们的过滤器会先于原来的过滤器执行,因为它的功能与老过滤器完全一样,所以这就等于把原来的过滤器替换掉了 --> <http auto-config='true' access-denied-page="/accessDenied.jsp"> <custom-filter ref="filterSecurityInterceptor" before="FILTER_SECURITY_INTERCEPTOR" /> </http> <!-- users-by-username-query为根据用户名查找用户,系统通过传入的用户名查询当前用户的登录名,密码和是否被禁用这一状态。authorities-by-username-query为根据用户名查找权限,系统通过传入的用户名查询当前用户已被授予的所有权限 --> <authentication-manager> <authentication-provider> <!-- 增加MD5加密 --> <password-encoder hash="md5"> <!-- 盐值加密:在password-encoder下添加了salt-source,并且指定使用username作为盐值 --> <salt-source user-property="username"/> </password-encoder> <jdbc-user-service data-source-ref="dataSource" cache-ref="userCache" users-by-username-query="select username,password,status as enabled from user where username=?" authorities-by-username-query="select u.username,r.name as authority from user u join user_role ur on u.id=ur.user_id join role r on r.id=ur.role_id where u.username=?" /> </authentication-provider> </authentication-manager> <!-- 缓存begin --> <b:bean id="userCache" class="org.springframework.security.core.userdetails.cache.EhCacheBasedUserCache"> <b:property name="cache" ref="userEhCache" /> </b:bean> <b:bean id="userEhCache" class="org.springframework.cache.ehcache.EhCacheFactoryBean"> <b:property name="cacheManager" ref="cacheManager" /> <b:property name="cacheName" value="userCache" /> </b:bean> <b:bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" /> <!-- 缓存end --> <b:bean id="filterSecurityInterceptor" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor" autowire="byType"> <b:property name="securityMetadataSource" ref="filterInvocationSecurityMetadataSource" /> <b:property name="authenticationManager" ref="org.springframework.security.authenticationManager" /> </b:bean> <b:bean id="filterInvocationSecurityMetadataSource" class="com.github.humeng126.security_01.JdbcFilterInvocationDefinitionSourceFactoryBean"> <b:property name="dataSource" ref="dataSource" /> <b:property name="resourceQuery" value=" select re.res_string,r.name from role r join resc_role rr on r.id=rr.role_id join resc re on re.id=rr.resc_id order by re.priority " /> </b:bean> <b:bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <b:property name="locations"> <b:list> <b:value>classpath*:application.properties</b:value> </b:list> </b:property> </b:bean> <!-- 数据源配置, 使用DBCP数据库连接池 --> <b:bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <!-- Connection Info --> <b:property name="driverClassName" value="${jdbc.driver}" /> <b:property name="url" value="${jdbc.url}" /> <b:property name="username" value="${jdbc.username}" /> <b:property name="password" value="${jdbc.password}" /> <!-- Connection Pooling Info --> <b:property name="maxActive" value="${dbcp.maxActive}" /> <b:property name="maxIdle" value="${dbcp.maxIdle}" /> <b:property name="defaultAutoCommit" value="false" /> <!-- 连接Idle一个小时后超时 --> <b:property name="timeBetweenEvictionRunsMillis" value="3600000" /> <b:property name="minEvictableIdleTimeMillis" value="3600000" /> </b:bean> </b:beans>
表里面的基本信息,业务系统可以根据自己的需求灵活定制
-- 资源 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);
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);
package com.github.humeng126.security_01; 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.util.matcher.AntPathRequestMatcher; import org.springframework.security.web.util.matcher.RequestMatcher; public class JdbcFilterInvocationDefinitionSourceFactoryBean extends JdbcDaoSupport implements FactoryBean { private String resourceQuery; public Object getObject() throws Exception { return new DefaultFilterInvocationSecurityMetadataSource( this.buildRequestMap()); } public Class getObjectType() { return FilterInvocationSecurityMetadataSource.class; } public boolean isSingleton() { return true; } protected Map<String, String> findResources() { ResourceMapping resourceMapping = new ResourceMapping(getDataSource(), resourceQuery); Map<String, String> resourceMap = new LinkedHashMap<String, String>(); // 执行它的execute()方法获得所有资源信息 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<ConfigAttribute>> requestMap = null; requestMap = new LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>>(); ConfigAttributeEditor editor = new ConfigAttributeEditor(); Map<String, String> resourceMap = this.findResources(); // 使用urlMatcher和requestMap创建DefaultFilterInvocationDefinitionSource for (Map.Entry<String, String> entry : resourceMap.entrySet()) { String key = entry.getKey(); editor.setAsText(entry.getValue()); requestMap.put(new AntPathRequestMatcher(key), (Collection<ConfigAttribute>) editor.getValue()); } return requestMap; } // 通过定义一个MappingSqlQuery实现数据库操作 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; } } 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; } } public String getResourceQuery() { return resourceQuery; } public void setResourceQuery(String resourceQuery) { this.resourceQuery = resourceQuery; } }
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <%@page import="org.springframework.context.ApplicationContext"%> <%@page import="org.springframework.web.context.support.WebApplicationContextUtils"%> <%@page import="org.springframework.beans.factory.FactoryBean"%> <%@page import="org.springframework.security.web.access.intercept.FilterSecurityInterceptor"%> <%@page import="org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource"%> <% ApplicationContext ctx = WebApplicationContextUtils .getWebApplicationContext(application); FactoryBean factoryBean = (FactoryBean) ctx .getBean("&filterInvocationSecurityMetadataSource"); FilterInvocationSecurityMetadataSource fids = (FilterInvocationSecurityMetadataSource) factoryBean .getObject(); FilterSecurityInterceptor filter = (FilterSecurityInterceptor) ctx .getBean("filterSecurityInterceptor"); filter.setSecurityMetadataSource(fids); %> <jsp:forward page="/" /> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title></title> </head> <body> </body> </html>