最近一直在學習spring security3,試着搭建了環境:html
項目配置pom.xml文件java
<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>
表裏面的基本信息,業務系統能夠根據本身的需求靈活定製mysql
-- 資源 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>