Spring security3

时间:2022-06-09 13:23:18

最近一直在学习spring security3,试着搭建了环境:

  • 构建maven环境

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>
  • 在web.xml配置文件增加filter
<?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>
  • spring的applicationContext.xml增加权限配置
    <?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);

Spring security3

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>