Spring security3

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

  • 构建maven环境

image

项目配置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);

image

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>
posted @ 2014-06-03 16:26  humeng126  阅读(921)  评论(0编辑  收藏  举报