- 浏览: 5543 次
- 性别:
- 来自: 上海
最新评论
源文件和word文档都在附件里
Spring Security.doc
-----------------------
目录
目录 1
前言 1
我们自己如何实现: 1
Spring Security是什么: 2
Spring Security能做什么: 2
为什么使用Spring Security: 2
Spring Security原理: 2
怎么用security: 2
本实例运行环境 3
最简单配置 3
配置security 5
1首先是建表,我们直接使用mysql的test数据库建立以下5个表格 5
2.建立web应用,开始配置 6
1.在配置文件里加入命名空间 6
2.配置数据源(如果你已经在spring配置文件里配置了略过此步骤) 7
3.配置http标签 7
4.配置认证提供器 8
5.实现安全过滤拦截器 9
6.配置web.xml 10
例子 14
将SecurityDemo添加到你的项目 14
附 15
不用重启系统使资源配置生效 15
Spring Security提供了如下内容的控制: 15
内置截器解释 17
前言
如果不想看下面这些,可直接从怎么用配置security章节开始看
我们自己如何实现:
1.登录验证,把登陆者信息放session里
2.每个action(servlet)里判断,需重复编码且要拦截不通过action(servlet)的action需要另外解决(如:jsp放webinfo下,页面判断等),不可取.
还有一个就是filter里判断,如果要做的很好做到可扩展性,需要很多编码,而security就是一个基于filter的实现,
Spring Security是什么:
spring框架下的一个子项目,acegi2.o,它主要用来提供安全服务,如果接触过spring,了解aop,依赖注入,代理,很快就能上手,如果对拦截器,增强器了解会更容易,就算你不会spring也没关系,照着后面的配置security章节做就可以了.
Spring Security能做什么:
url拦截,方法拦截,session拦截(如单点登录),加密…,如果想详细了解可以参考后面的Spring Security提供了如下内容的控制章节
为什么使用Spring Security:
1.提供了一套权限框架,这套框架是可行的;
2.提供了很多用户身份认证功能,可以节约大量开发工作;
3. 提供了角色判断功能
4. 提供了form-login、remember me等控制。
Spring Security原理:
Spring使用由Filter组成的Chain,来判断权限, Spring提供了一些Filter,也支持开发者自定义Filter。链里有些filter是可组装的,这是他的灵活之处,但有些必须的(自动维护)。
怎么用security:
后面配置security章节将会讲到,大体步骤就是:
1.配置security配置文件
1、 配置<http>
(<http>元素会创建一个FilterChainProxy,内置了一些拦截器,还可以在这里配置登录页面,不拦截页面,退出,是否单点登录…,)
2、 配置认证管理器<authentication-provider>
(通过name1获得用户名密码,2用户名和角色(权限))
3、 配置安全拦截器(此步骤是可选择的,根据定义的规则拦截url,方法)
2.配置web.xml
如果想更详细的了解你也可以参考security中文文档,
Spring Security版本号是一个包含三个整数的组合:主要版本号.次要版本号.补丁。 基本思路是主要版本是不兼容的(所有如果用我给的例子一定要注意版本号), 次要版本号在源代码和二进制要与老版本保持兼容,补丁则意味着向前向后的完全兼容。
本实例运行环境
Jdk1.5+apache-tomcat-5.5.23+mysql
依赖以下jar包:
1.spring framework 2.5-rc2:
spring-aop.jar
spring-beans.jar
spring-context.jar
spring-core.jar
spring-jdbc.jar
spring-tx.jar
spring-web.jar
亦可导入只导入full jar FULL JAR spring.jar或导入全部jar包
2.spring security 2.04:
spring-security-core-2.0.4.jar
spring-security-core-tiger-2.0.4.jar
3.mysql驱动
mysql-connector-java-5.1.6-bin.jar
spring security 2.04 jar包下载地址
http://sourceforge.net/projects/springframework/files/spring-security/2.0.4/spring-security-2.0.4.zip/download
最简单配置
如果你想体验以下security,下面是最简配置
1.配置security
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="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-2.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.1.xsd">
<http auto-config="true">
<intercept-url pattern="/index.jsp" filters="none"/>
<intercept-url pattern="/*user*" access="ROLE_USER"/>
<intercept-url pattern="/*admin*" access="ROLE_ADMIN"/>
</http>
<authentication-provider>
<user-service>
<user name="admin" password="admin" authorities="ROLE_USER, ROLE_ADMIN" />
<user name="user" password="user" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</beans:beans>
当然你要提供index.jsp(包含跳到admin.jsp和user.jsp的链接),admin.jsp,user.jsp页面,这三个页面都是一个普通页面,你会发现从index上面的链接你是跳不到后面两个页面的
2.配置web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>SecurityDemo</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/applicationContext-security.xml
</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<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>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
配置security
1首先是建表,我们直接使用mysql的test数据库建立以下5个表格
一个用户有多个角色(多对多)
一个角色可以访问多个资源(据情况而定是一对多,还是多对多)
/*用户表:用户名,密码,是否可以使用(0:可以,1:不可以)*/
CREATE TABLE `user` (
`id` int(11) NOT NULL auto_increment,
`name` varchar(255) default NULL,
`password` varchar(255) default NULL,
`enabled` int(1) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*角色表*/
CREATE TABLE `role` (
`id` int(11) NOT NULL auto_increment,
`name` varchar(255) default NULL,
`description` varchar(255) default NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*用户角色关联表*/
/*用户角色关联表*/
CREATE TABLE `user_role` (
`user_id` int(11) NOT NULL,
`role_id` int(11) NOT NULL,
PRIMARY KEY (`user_id`,`role_id`),
KEY `FK143BF46AF6AD4381` (`user_id`),
KEY `FK143BF46A51827FA1` (`role_id`),
CONSTRAINT `FK143BF46A51827FA1` FOREIGN KEY (`role_id`) REFERENCES `role` (`id`),
CONSTRAINT `FK143BF46AF6AD4381` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
/*资源表*/
CREATE TABLE `resource` (
`id` int(11) NOT NULL auto_increment,
`type` varchar(255) default NULL,
`value` varchar(255) default NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*角色资源表管理表*/
CREATE TABLE `role_resource` (
`role_id` int(11) NOT NULL,
`resource_id` int(11) NOT NULL,
PRIMARY KEY (`role_id`,`resource_id`),
KEY `FKAEE599B751827FA1` (`role_id`),
KEY `FKAEE599B7EFD18D21` (`resource_id`),
CONSTRAINT `FKAEE599B751827FA1` FOREIGN KEY (`role_id`) REFERENCES `role` (`id`),
CONSTRAINT `FKAEE599B7EFD18D21` FOREIGN KEY (`resource_id`) REFERENCES `resource` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
2.建立web应用,开始配置
将依赖的jar包拷入WEB-INF/lib下,在WEB-INF下建立配置文件:
applicationContext-security.xml
1.在配置文件里加入命名空间
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="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-2.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-2.0.1.xsd">
<!--下面的配置写在这里-->
</beans:beans>
2.配置数据源(如果你已经在spring配置文件里配置了略过此步骤)
<beans:bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<beans:property name="driverClassName"
value="com.mysql.jdbc.Driver" />
<beans:property name="url"
value="jdbc:mysql://localhost:3306/test" />
<beans:property name="username" value="root" />
<beans:property name="password" value="111111" />
</beans:bean>
3.配置http标签
access-denied-page:没有权限访问拒绝页面,
form-login登录页面,如果不写会自动分配一个,
如果是自定义登录页面用户名和密码输入框的name属性必须叫j_username 和 j_password
default-targer-url登录成功后默认到达页面,其实在你没有登录而去访问某个页面时被拦截登录之后会跳到之前你访问的页面
如果项目必须从某个页面开始浏览则加上always-use-default-target="true"
logout添加一个LogoutFilter到过滤器堆栈中
logout-url这个URL会触发注销操作(比如,会被过滤器处理)
默认是"/j_spring_security_logout"。
logout-success-url属性,用户在注销后转向的URL。 默认是"/"。
auto-config属性,其实是下面这些配置的缩写:
<http><form-login /> <http-basic /><logout /> </http>
这里使用最小 <http>配置
<http auto-config="true" access-denied-page="/deniedPage.jsp">
<form-login default-target-url="/index.jsp" login-page="/login.jsp" />
<logout logout-url="/my_logout" logout-success-url="/index.jsp" />
</http>
在<http>节点维护了一系列的建立了web安全配置的安全过滤器。 一些核心的过滤器总是要被创建的(防止session攻击,处理异常,安全拦截器),其他的将根据子元素的配置添加到过滤器队列中(也就是说一个元素标签都会对应一个拦截器)。 标准过滤器的位置都是固定的,这避免了之前版本中的一个常见问题,如果你想更详细的了解这些过滤器的作用和顺序可参考后面章节内置截器解释
4.配置认证提供器
就是告诉security怎样获得用户对应权限,它有几个默认实现
1,内存<user-service>
2,jdbc <jdbc-user-service data-source-ref="dataSource"
3,ldap:<ldap-user-service/>
他们是可以结合使用的
这里我们使用默认的jdbc实现,从数据库获得,
官方给了默认的表结构大概是这样
CREATE TABLE users (
username VARCHAR(50) NOT NULL PRIMARY KEY,
password VARCHAR(50) NOT NULL,
enabled BIT NOT NULL
);
CREATE TABLE authorities (
username VARCHAR(50) NOT NULL,
authority VARCHAR(50) NOT NULL
);
这里我们不用这个表而使用逻辑主键ID标示每个User和每个Authorities(Role)。而且从典型意义上讲,他们之间是一个多对多的关系
因为我们改变了默认表结构还想使用默认的认证提供器,所有以下两个元素会很有用
jdbc-user-service data-source-ref:数据库认证
users-by-username-query:根据用户名查找用户
authorities-by-username-query:根据用户名查找这个用户所有的角色名
这里需要特别说明的是:
users-by-username-query返回的三列必须是:username, password, enabled(非0时表示账号可用)
authorities-by-username-query指定的查询,必须至少按顺序返回2列,第一列列名必须是username,第2列数据必须是权限
<authentication-provider>
<jdbc-user-service data-source-ref="dataSource"
users-by-username-query="
select u.name username,u.password password,u.enabled enabled
from user u where u.name=?"
authorities-by-username-query="
select u.name username,r.description authority
from user_role ur
join user u on ur.user_id=u.id
join role r on ur.role_id=r.id
where u.name=?"
/>
</authentication-provider>
5.实现安全过滤拦截器
拦截数据库配置的url,只有当你的角色和资源在数据库中管理,你才能访问该url
拦截器的实现思路
1, 从数据库中获得角色和资源的关联关系(dao)
2, 获得客户端访问的url(怎么获得,这就需要你实现filter)
3, 把url和数据库里比较(决策器投票,你不需要关心细节),看你的角色是否可以访问该资源,没有权限就会抛出一个异常,系统会自动分配一个访问拒绝页面,我们也可以在http标签里通过access-denied-page指定
4, 把拦截器放入拦截链中
下面给我一个我的实现,也许你会不明白为什么还要第二步,为什么不是实现filter,而是返回这个陌生类的一个实例,讲完下面3步完配置之后我会说明
1.配置一个普通的javaBean
此javabean负责从数据库里查询资源和角色的关联关系,你可以用jdbc,hibernate等等任意实现,这将在下一步用到
<beans:bean id="urlRoleDao" class="dao.UrlRoleDao">
<beans:constructor-arg ref="dataSource" />
<beans:constructor-arg value="
select rs.value,r.description
from role_resource rr
join resource rs on rr.resource_id=rs.id
join role r on rr.role_id=r.id
" />
</beans:bean>
2.创建一个对请求(url)拦截(捕获)的过滤器实例
它的匹配是通过注入上面的javabean从数据库查找的,对于url匹配规则有ant和正则两种
你可以通过这里注入,我的是写死在程序里的
<beans:bean id="filterInvocationDefinitionSource"
class="filters.CustomObjectDefinitionSource">
<beans:property name="urlRoleDao" ref="urlRoleDao" />
</beans:bean>
3.实现安全拦截器并放入到过滤链中
FILTER_SECURITY_INTERCEPTOR是http标签内置的安全拦截器(intercept-url),我们将自己的拦截器放入它之前关于这个请参考内置截器解释章节的图1
<beans:bean id="filterSecurityInterceptor" autowire="byType"
class="org.springframework.security.intercept.web.FilterSecurityInterceptor"
>
<custom-filter before="FILTER_SECURITY_INTERCEPTOR"/>
<beans:property name="objectDefinitionSource" ref="filterInvocationDefinitionSource" />
</beans:bean>
FilterSecurityInterceptor(安全拦截器) 用来处理HTTP资源的安全。需要三个bean
1, 认证提供器 2.决策器配置了3 。资源,1,2 都是autowire=“byType”自动装配的,它其实就是装配了这两个东西:
<beans:property name="authenticationManager" ref="_authenticationManager" />
<beans:property name="accessDecisionManager" ref="_accessManager" />
而这两个类是命名空间内置的,在服务器启动的时候,你可以在控制台看到它们
objectDefinitionSource其实就是source接受什么样的角色,这里有个acegi的配置,可以参考一下
<property name="objectDefinitionSource">
<value>
/logoff.jsp=ROLE_ANONYMOUS,ROLE_USER
/switchuser.jsp=ROLE_SUPERVISOR
</value>
</property name="objectDefinitionSource">
为了不把要拦截的url写死在配置文件里,你需要写你自己的objectDefinitionSource(资源对象),通过依赖注入,注入到安全拦截器中,
应当注意的是FilterSecurityInterceptor.setObjectDefinitionSource()方法其实期望一个
FilterInvocationDefinitionSource(他其实是objectDefinitionSource的子接口)实例。而
DefaultFilterInvocationDefinitionSource是接口FilterInvocationDefinitionSource的子类实现
我用FactoryBean获取了它所管理的DefaultFilterInvocationDefinitionSource实例引用
这里就解释了为什么会有第二步并且那么做
6.配置web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/applicationContext-security.xml
</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<!-- -
<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>
到此security的所有配置已经完成
applicationContext-security.xml的全部配置:
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="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-2.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-2.0.1.xsd">
<!--数据源-->
<beans:bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<beans:property name="driverClassName"
value="com.mysql.jdbc.Driver" />
<beans:property name="url"
value="jdbc:mysql://localhost:3306/test" />
<beans:property name="username" value="root" />
<beans:property name="password" value="111111" />
</beans:bean>
<!—配置http验证-->
<http auto-config="true" access-denied-page="/deniedPage.jsp">
<form-login default-target-url="/index.jsp"
login-page="/login.jsp" />
<logout logout-url="/my_logout" logout-success-url="/index.jsp" />
</http>
<!-- 配置认证提供器 -->
<authentication-provider>
<jdbc-user-service data-source-ref="dataSource"
users-by-username-query="
select u.name username,u.password password,
u.enabled enabled
from user u where u.name=?"
authorities-by-username-query="
select u.name username,r.description authority
from user_role ur
join user u on ur.user_id=u.id
join role r on ur.role_id=r.id
where u.name=?" />
</authentication-provider>
<!-- 配置一个普通的javaBean,此javabean负责从数据库里查询资源和角色的关联关系, -->
<beans:bean id="urlRoleDao" class="dao.UrlRoleDao">
<beans:constructor-arg ref="dataSource" />
<beans:constructor-arg
value="
select rs.value,r.description
from role_resource rr
join resource rs on rr.resource_id=rs.id
join role r on rr.role_id=r.id
" />
</beans:bean>
<!-- 定义自定义过滤器 -->
<beans:bean id="filterInvocationDefinitionSource"
class="filters.CustomObjectDefinitionSource">
<beans:property name="urlRoleDao" ref="urlRoleDao" />
</beans:bean>
<!—实现拦截器,并放入到过滤链中 -->
<beans:bean id="filterSecurityInterceptor" autowire="byType"
class="org.springframework.security.intercept.web.FilterSecurityInterceptor">
<custom-filter before="FILTER_SECURITY_INTERCEPTOR" />
<beans:property name="objectDefinitionSource"
ref="filterInvocationDefinitionSource" />
</beans:bean>
</beans:beans>
全部的web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>SecurityDemo</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/applicationContext-security.xml
</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<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>
<servlet>
<description></description>
<display-name>ToUserHome</display-name>
<servlet-name>toUserHome</servlet-name>
<servlet-class>servlet.ToUserHome</servlet-class>
</servlet>
<servlet>
<description></description>
<display-name>ToAdminHome</display-name>
<servlet-name>ToAdminHome</servlet-name>
<servlet-class>servlet.ToAdminHome</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>toUserHome</servlet-name>
<url-pattern>/toUserHome</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>ToAdminHome</servlet-name>
<url-pattern>/toAdminHome</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
例子
这里我给了这个完整的例子SecurityDemo.zip,把数据库密码改掉,建立上面的表(配置security第一步),
插入一下数据,项目就可以运行了
insert into resource values(1,'url','/*admin*');
insert into resource values(2,'url','/*user*');
insert into role values(1,'管理员','ROLE_ADMIN');
insert into role values(2,'普通用户','ROLE_USER');
insert into user values(1,'admin','admin',1);
insert into user values(2,'user','user',1);
insert into role_resource values(1,1);
insert into role_resource values(2,2);
insert into user_role values(1,1);
insert into user_role values(1,2);
insert into user_role values(2,2);
各页面介绍
login.jsp登录页面,index主页,adminPage.jsp管理员角色主页,需要有管理员权限才能访问userPage.jsp普通用户主页,需要有用户权限才能访问
其中管理员页面和陪同用户页面时只有相应权限的人才能访问。
关于例子里面过滤器实现类的介绍:
代码里有详细注释,先看类级别的注释,最主要的就是那个过滤器类
将SecurityDemo添加到你的项目
如果你有不同的表结构,只需改动第四步和第五步里面的sql语句,但要注意红色字体部分的说明
附
以下都是引用的外部资料
不用重启系统使资源配置生效
目前存在的问题是,系统会在初始化时一次将所有资源加载到内存中,即使在数据库中修改了资源信息,系统也不会再次去从数据库中读取资源信息。这就造成了每次修改完数据库后,都需要重启系统才能时资源配置生效。
解决方案是,如果数据库中的资源出现的变化,需要刷新内存中已加载的资源信息时,使用下面代码:
<%@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.intercept.web.FilterSecurityInterceptor"%>
<%@page import="org.springframework.security.intercept.web.FilterInvocationDefinitionSource"%>
<%
ApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(application);
FactoryBean factoryBean = (FactoryBean) ctx.getBean("&filterInvocationDefinitionSource");
FilterInvocationDefinitionSource fids = (FilterInvocationDefinitionSource) factoryBean.getObject();
FilterSecurityInterceptor filter = (FilterSecurityInterceptor) ctx.getBean("filterSecurityInterceptor");
filter.setObjectDefinitionSource(fids);
%>
<jsp:forward page="/"/>
Spring Security提供了如下内容的控制:
1. url;
2. bean method;
3. http session。
url:可以分为需要权限判断的url,不需要权限判断的url,登录表单url。通过我对spring相关帖子和参考文档的阅读,需要权限判断的url。仅限于做角色判断,就是说判断当前用户是否具有指定的角色。
bean method:Spring支持对Service layer method做权限判断。通过我对spring相关帖子和参考文档的阅读,也仅限于做角色判断。配置方式有2种:
1. 写在Java源代码里面,如:@Secured("ROLE_TELLER")(该方法只有具有TELLER角色的用户能够访问,否则抛出异常);
2. 写在配置文件里面,如:<protect method="set*" access="ROLE_ADMIN" />(该bean的所有set方法,只有具有ADMIN角色的用户能够访问,否则抛出异常)。
http session:控制一个用户名是否能重复登录,以及重复登录次数,并非重试密码次数。
另外,Spring Security还提供了如下一些功能:
1. remember me,记住我;
2. form-login登录控制;
3. 多种身份认证功能;
4. 用户密码加密和“salt”功能;
5. http协议控制;
6. 访问端口控制;
7. Pre-Invocation & After-Invocation。
remember me,记住我:还记得浏览器采用cookie记住用户名和密码自动登录吗?好像就是这个(不知道我理解错了没有,应该没有。只是我不大敢相信)。使用这个功能,开发者在登录页面,使用spring自定义的标签。
form-login登录控制:有些页面不允许匿名访问,那么当匿名访问这些页面的时候,将弹出(或者转到)form-login窗口(或者页面)。这里又牵引出2个问题:1,输入用户名和密码后怎样验证;2,密码是否需要加密,怎么加密。
多种身份认证功能:Spring提供了丰富的用户身份认证功能。身份认证是什么意思?比如您告诉我“我是神仙”。那么我会问您“凭什么证明您是神仙”。这就是身份认证。认证手段一般是保存到数据库表的用户名/密码,usb key,ldap等。一般情况下,我们都使用用户名/密码的。
用户密码加密和“salt”功能:密码采用md5,还是sha加密算法。如果我们对密码加密的时候,不想仅仅对密码加密,还想把用户名和密码放在一起加密做为加密后的密码。那么使用salt吧。salt支持也读取用户的其他属性,不仅是用户名。
http协议控制:哪些url,必须采用https访问呢?哪些url必须采用http访问呢?哪些又两者都可以呢?通过这个配置。
访问端口控制:类似http协议控制,控制url和访问端口之间的关系。
内置截器解释
图1
HttpSessionContextIntegrationFilter:
率先判断用户的session中是否已经存在一个SecurityContext了。如果存在,就把 SecurityContext拿出来,放到SecurityContextHolder中,供Spring Security的其他部分使用。如果不存在,就创建一个SecurityContext出来,还是放到SecurityContextHolder中,供Spring Security的其他部分使用。
用途二,在所有过滤器执行完毕后,清空SecurityContextHolder,因为SecurityContextHolder是基于ThreadLocal的,如果在操作完成后清空ThreadLocal,会受到服务器的线程池机制的影响。
LogoutFilter:
用途是在用户发送注销请求时,销毁用户session,清空SecurityContextHolder,然后重定向到注销成功页面。可以与rememberMe之类的机制结合,在注销的同时清空用户cookie。
AuthenticationProcessingFilter:
处理form登陆的过滤器,与form登陆有关的所有操作都是在此进行的。
默认情况下只处理/j_spring_security_check请求,这个请求应该是用户使用form登陆后的提交地址,
此过滤器执行的基本操作时,通过用户名和密码判断用户是否有效,如果登录成功就跳转到成功页面(可能是登陆之前访问的受保护页面,也可能是默认的成功页面),如果登录失败,就跳转到失败页面。
DefaultLoginPageGeneratingFilter
此过滤器用来生成一个默认的登录页面,默认的访问地址为/spring_security_login,这个默认的登录页面虽然支持用户输入用户名,密码,也支持rememberMe功能,但是因为太难看了,只能是在演示时做个样子,不可能直接用在实际项目中。
BasicProcessingFilter
此过滤器用于进行basic验证,功能与AuthenticationProcessingFilter类似,只是验证的方式不同。
SecurityContextHolderAwareRequestFilter
此过滤器用来包装客户的请求。目的是在原始请求的基础上,为后续程序提供一些额外的数据。比如getRemoteUser()时直接返回当前登陆的用户名之类的。
RememberMeProcessingFilter
此过滤器实现RememberMe功能,当用户cookie中存在rememberMe的标记,此过滤器会根据标记自动实现用户登陆,并创建SecurityContext,授予对应的权限。
AnonymousProcessingFilter
为了保证操作统一性,当用户没有登陆时,默认为用户分配匿名用户的权限。
ExceptionTranslationFilter
此过滤器的作用是处理中FilterSecurityInterceptor抛出的异常,然后将请求重定向到对应页面,或返回对应的响应错误代码。
SessionFixationProtectionFilter
防御session固化攻击。
FilterSecurityInterceptor
用户的权限控制都包含在这个过滤器中。
功能一:如果用户尚未登陆,则抛出AuthenticationCredentialsNotFoundException“尚未认证异常”。
功能二:如果用户已登录,但是没有访问当前资源的权限,则抛出AccessDeniedException“拒绝访问异常”。
功能三:如果用户已登录,也具有访问当前资源的权限,则放行。
注:SecurityContextHolder对象 我们把当前应用程序的当前安全环境的细节存储到它里边了, 它也包含了应用当前使用的主体细节。 默认情况下,SecurityContextHolder使用ThreadLocal存储这些信息, 这意味着,安全环境在同一个线程执行的方法一直是有效的, 即使这个安全环境没有作为一个方法参数传递到那些方法里。 这种情况下使用ThreadLocal是非常安全的, 只要记得在处理完当前主体的请求以后,把这个线程清除就行了。 当然,Spring Security自动帮你管理这一切了, 你就不用担心什么了。
SecurityContext对象,保存Authentication信息,和请求对应的安全信息。
Spring Security.doc
-----------------------
目录
目录 1
前言 1
我们自己如何实现: 1
Spring Security是什么: 2
Spring Security能做什么: 2
为什么使用Spring Security: 2
Spring Security原理: 2
怎么用security: 2
本实例运行环境 3
最简单配置 3
配置security 5
1首先是建表,我们直接使用mysql的test数据库建立以下5个表格 5
2.建立web应用,开始配置 6
1.在配置文件里加入命名空间 6
2.配置数据源(如果你已经在spring配置文件里配置了略过此步骤) 7
3.配置http标签 7
4.配置认证提供器 8
5.实现安全过滤拦截器 9
6.配置web.xml 10
例子 14
将SecurityDemo添加到你的项目 14
附 15
不用重启系统使资源配置生效 15
Spring Security提供了如下内容的控制: 15
内置截器解释 17
前言
如果不想看下面这些,可直接从怎么用配置security章节开始看
我们自己如何实现:
1.登录验证,把登陆者信息放session里
2.每个action(servlet)里判断,需重复编码且要拦截不通过action(servlet)的action需要另外解决(如:jsp放webinfo下,页面判断等),不可取.
还有一个就是filter里判断,如果要做的很好做到可扩展性,需要很多编码,而security就是一个基于filter的实现,
Spring Security是什么:
spring框架下的一个子项目,acegi2.o,它主要用来提供安全服务,如果接触过spring,了解aop,依赖注入,代理,很快就能上手,如果对拦截器,增强器了解会更容易,就算你不会spring也没关系,照着后面的配置security章节做就可以了.
Spring Security能做什么:
url拦截,方法拦截,session拦截(如单点登录),加密…,如果想详细了解可以参考后面的Spring Security提供了如下内容的控制章节
为什么使用Spring Security:
1.提供了一套权限框架,这套框架是可行的;
2.提供了很多用户身份认证功能,可以节约大量开发工作;
3. 提供了角色判断功能
4. 提供了form-login、remember me等控制。
Spring Security原理:
Spring使用由Filter组成的Chain,来判断权限, Spring提供了一些Filter,也支持开发者自定义Filter。链里有些filter是可组装的,这是他的灵活之处,但有些必须的(自动维护)。
怎么用security:
后面配置security章节将会讲到,大体步骤就是:
1.配置security配置文件
1、 配置<http>
(<http>元素会创建一个FilterChainProxy,内置了一些拦截器,还可以在这里配置登录页面,不拦截页面,退出,是否单点登录…,)
2、 配置认证管理器<authentication-provider>
(通过name1获得用户名密码,2用户名和角色(权限))
3、 配置安全拦截器(此步骤是可选择的,根据定义的规则拦截url,方法)
2.配置web.xml
如果想更详细的了解你也可以参考security中文文档,
Spring Security版本号是一个包含三个整数的组合:主要版本号.次要版本号.补丁。 基本思路是主要版本是不兼容的(所有如果用我给的例子一定要注意版本号), 次要版本号在源代码和二进制要与老版本保持兼容,补丁则意味着向前向后的完全兼容。
本实例运行环境
Jdk1.5+apache-tomcat-5.5.23+mysql
依赖以下jar包:
1.spring framework 2.5-rc2:
spring-aop.jar
spring-beans.jar
spring-context.jar
spring-core.jar
spring-jdbc.jar
spring-tx.jar
spring-web.jar
亦可导入只导入full jar FULL JAR spring.jar或导入全部jar包
2.spring security 2.04:
spring-security-core-2.0.4.jar
spring-security-core-tiger-2.0.4.jar
3.mysql驱动
mysql-connector-java-5.1.6-bin.jar
spring security 2.04 jar包下载地址
http://sourceforge.net/projects/springframework/files/spring-security/2.0.4/spring-security-2.0.4.zip/download
最简单配置
如果你想体验以下security,下面是最简配置
1.配置security
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="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-2.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.1.xsd">
<http auto-config="true">
<intercept-url pattern="/index.jsp" filters="none"/>
<intercept-url pattern="/*user*" access="ROLE_USER"/>
<intercept-url pattern="/*admin*" access="ROLE_ADMIN"/>
</http>
<authentication-provider>
<user-service>
<user name="admin" password="admin" authorities="ROLE_USER, ROLE_ADMIN" />
<user name="user" password="user" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</beans:beans>
当然你要提供index.jsp(包含跳到admin.jsp和user.jsp的链接),admin.jsp,user.jsp页面,这三个页面都是一个普通页面,你会发现从index上面的链接你是跳不到后面两个页面的
2.配置web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>SecurityDemo</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/applicationContext-security.xml
</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<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>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
配置security
1首先是建表,我们直接使用mysql的test数据库建立以下5个表格
一个用户有多个角色(多对多)
一个角色可以访问多个资源(据情况而定是一对多,还是多对多)
/*用户表:用户名,密码,是否可以使用(0:可以,1:不可以)*/
CREATE TABLE `user` (
`id` int(11) NOT NULL auto_increment,
`name` varchar(255) default NULL,
`password` varchar(255) default NULL,
`enabled` int(1) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*角色表*/
CREATE TABLE `role` (
`id` int(11) NOT NULL auto_increment,
`name` varchar(255) default NULL,
`description` varchar(255) default NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*用户角色关联表*/
/*用户角色关联表*/
CREATE TABLE `user_role` (
`user_id` int(11) NOT NULL,
`role_id` int(11) NOT NULL,
PRIMARY KEY (`user_id`,`role_id`),
KEY `FK143BF46AF6AD4381` (`user_id`),
KEY `FK143BF46A51827FA1` (`role_id`),
CONSTRAINT `FK143BF46A51827FA1` FOREIGN KEY (`role_id`) REFERENCES `role` (`id`),
CONSTRAINT `FK143BF46AF6AD4381` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
/*资源表*/
CREATE TABLE `resource` (
`id` int(11) NOT NULL auto_increment,
`type` varchar(255) default NULL,
`value` varchar(255) default NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*角色资源表管理表*/
CREATE TABLE `role_resource` (
`role_id` int(11) NOT NULL,
`resource_id` int(11) NOT NULL,
PRIMARY KEY (`role_id`,`resource_id`),
KEY `FKAEE599B751827FA1` (`role_id`),
KEY `FKAEE599B7EFD18D21` (`resource_id`),
CONSTRAINT `FKAEE599B751827FA1` FOREIGN KEY (`role_id`) REFERENCES `role` (`id`),
CONSTRAINT `FKAEE599B7EFD18D21` FOREIGN KEY (`resource_id`) REFERENCES `resource` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
2.建立web应用,开始配置
将依赖的jar包拷入WEB-INF/lib下,在WEB-INF下建立配置文件:
applicationContext-security.xml
1.在配置文件里加入命名空间
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="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-2.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-2.0.1.xsd">
<!--下面的配置写在这里-->
</beans:beans>
2.配置数据源(如果你已经在spring配置文件里配置了略过此步骤)
<beans:bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<beans:property name="driverClassName"
value="com.mysql.jdbc.Driver" />
<beans:property name="url"
value="jdbc:mysql://localhost:3306/test" />
<beans:property name="username" value="root" />
<beans:property name="password" value="111111" />
</beans:bean>
3.配置http标签
access-denied-page:没有权限访问拒绝页面,
form-login登录页面,如果不写会自动分配一个,
如果是自定义登录页面用户名和密码输入框的name属性必须叫j_username 和 j_password
default-targer-url登录成功后默认到达页面,其实在你没有登录而去访问某个页面时被拦截登录之后会跳到之前你访问的页面
如果项目必须从某个页面开始浏览则加上always-use-default-target="true"
logout添加一个LogoutFilter到过滤器堆栈中
logout-url这个URL会触发注销操作(比如,会被过滤器处理)
默认是"/j_spring_security_logout"。
logout-success-url属性,用户在注销后转向的URL。 默认是"/"。
auto-config属性,其实是下面这些配置的缩写:
<http><form-login /> <http-basic /><logout /> </http>
这里使用最小 <http>配置
<http auto-config="true" access-denied-page="/deniedPage.jsp">
<form-login default-target-url="/index.jsp" login-page="/login.jsp" />
<logout logout-url="/my_logout" logout-success-url="/index.jsp" />
</http>
在<http>节点维护了一系列的建立了web安全配置的安全过滤器。 一些核心的过滤器总是要被创建的(防止session攻击,处理异常,安全拦截器),其他的将根据子元素的配置添加到过滤器队列中(也就是说一个元素标签都会对应一个拦截器)。 标准过滤器的位置都是固定的,这避免了之前版本中的一个常见问题,如果你想更详细的了解这些过滤器的作用和顺序可参考后面章节内置截器解释
4.配置认证提供器
就是告诉security怎样获得用户对应权限,它有几个默认实现
1,内存<user-service>
2,jdbc <jdbc-user-service data-source-ref="dataSource"
3,ldap:<ldap-user-service/>
他们是可以结合使用的
这里我们使用默认的jdbc实现,从数据库获得,
官方给了默认的表结构大概是这样
CREATE TABLE users (
username VARCHAR(50) NOT NULL PRIMARY KEY,
password VARCHAR(50) NOT NULL,
enabled BIT NOT NULL
);
CREATE TABLE authorities (
username VARCHAR(50) NOT NULL,
authority VARCHAR(50) NOT NULL
);
这里我们不用这个表而使用逻辑主键ID标示每个User和每个Authorities(Role)。而且从典型意义上讲,他们之间是一个多对多的关系
因为我们改变了默认表结构还想使用默认的认证提供器,所有以下两个元素会很有用
jdbc-user-service data-source-ref:数据库认证
users-by-username-query:根据用户名查找用户
authorities-by-username-query:根据用户名查找这个用户所有的角色名
这里需要特别说明的是:
users-by-username-query返回的三列必须是:username, password, enabled(非0时表示账号可用)
authorities-by-username-query指定的查询,必须至少按顺序返回2列,第一列列名必须是username,第2列数据必须是权限
<authentication-provider>
<jdbc-user-service data-source-ref="dataSource"
users-by-username-query="
select u.name username,u.password password,u.enabled enabled
from user u where u.name=?"
authorities-by-username-query="
select u.name username,r.description authority
from user_role ur
join user u on ur.user_id=u.id
join role r on ur.role_id=r.id
where u.name=?"
/>
</authentication-provider>
5.实现安全过滤拦截器
拦截数据库配置的url,只有当你的角色和资源在数据库中管理,你才能访问该url
拦截器的实现思路
1, 从数据库中获得角色和资源的关联关系(dao)
2, 获得客户端访问的url(怎么获得,这就需要你实现filter)
3, 把url和数据库里比较(决策器投票,你不需要关心细节),看你的角色是否可以访问该资源,没有权限就会抛出一个异常,系统会自动分配一个访问拒绝页面,我们也可以在http标签里通过access-denied-page指定
4, 把拦截器放入拦截链中
下面给我一个我的实现,也许你会不明白为什么还要第二步,为什么不是实现filter,而是返回这个陌生类的一个实例,讲完下面3步完配置之后我会说明
1.配置一个普通的javaBean
此javabean负责从数据库里查询资源和角色的关联关系,你可以用jdbc,hibernate等等任意实现,这将在下一步用到
<beans:bean id="urlRoleDao" class="dao.UrlRoleDao">
<beans:constructor-arg ref="dataSource" />
<beans:constructor-arg value="
select rs.value,r.description
from role_resource rr
join resource rs on rr.resource_id=rs.id
join role r on rr.role_id=r.id
" />
</beans:bean>
2.创建一个对请求(url)拦截(捕获)的过滤器实例
它的匹配是通过注入上面的javabean从数据库查找的,对于url匹配规则有ant和正则两种
你可以通过这里注入,我的是写死在程序里的
<beans:bean id="filterInvocationDefinitionSource"
class="filters.CustomObjectDefinitionSource">
<beans:property name="urlRoleDao" ref="urlRoleDao" />
</beans:bean>
3.实现安全拦截器并放入到过滤链中
FILTER_SECURITY_INTERCEPTOR是http标签内置的安全拦截器(intercept-url),我们将自己的拦截器放入它之前关于这个请参考内置截器解释章节的图1
<beans:bean id="filterSecurityInterceptor" autowire="byType"
class="org.springframework.security.intercept.web.FilterSecurityInterceptor"
>
<custom-filter before="FILTER_SECURITY_INTERCEPTOR"/>
<beans:property name="objectDefinitionSource" ref="filterInvocationDefinitionSource" />
</beans:bean>
FilterSecurityInterceptor(安全拦截器) 用来处理HTTP资源的安全。需要三个bean
1, 认证提供器 2.决策器配置了3 。资源,1,2 都是autowire=“byType”自动装配的,它其实就是装配了这两个东西:
<beans:property name="authenticationManager" ref="_authenticationManager" />
<beans:property name="accessDecisionManager" ref="_accessManager" />
而这两个类是命名空间内置的,在服务器启动的时候,你可以在控制台看到它们
objectDefinitionSource其实就是source接受什么样的角色,这里有个acegi的配置,可以参考一下
<property name="objectDefinitionSource">
<value>
/logoff.jsp=ROLE_ANONYMOUS,ROLE_USER
/switchuser.jsp=ROLE_SUPERVISOR
</value>
</property name="objectDefinitionSource">
为了不把要拦截的url写死在配置文件里,你需要写你自己的objectDefinitionSource(资源对象),通过依赖注入,注入到安全拦截器中,
应当注意的是FilterSecurityInterceptor.setObjectDefinitionSource()方法其实期望一个
FilterInvocationDefinitionSource(他其实是objectDefinitionSource的子接口)实例。而
DefaultFilterInvocationDefinitionSource是接口FilterInvocationDefinitionSource的子类实现
我用FactoryBean获取了它所管理的DefaultFilterInvocationDefinitionSource实例引用
这里就解释了为什么会有第二步并且那么做
6.配置web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/applicationContext-security.xml
</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<!-- -
<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>
到此security的所有配置已经完成
applicationContext-security.xml的全部配置:
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="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-2.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-2.0.1.xsd">
<!--数据源-->
<beans:bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<beans:property name="driverClassName"
value="com.mysql.jdbc.Driver" />
<beans:property name="url"
value="jdbc:mysql://localhost:3306/test" />
<beans:property name="username" value="root" />
<beans:property name="password" value="111111" />
</beans:bean>
<!—配置http验证-->
<http auto-config="true" access-denied-page="/deniedPage.jsp">
<form-login default-target-url="/index.jsp"
login-page="/login.jsp" />
<logout logout-url="/my_logout" logout-success-url="/index.jsp" />
</http>
<!-- 配置认证提供器 -->
<authentication-provider>
<jdbc-user-service data-source-ref="dataSource"
users-by-username-query="
select u.name username,u.password password,
u.enabled enabled
from user u where u.name=?"
authorities-by-username-query="
select u.name username,r.description authority
from user_role ur
join user u on ur.user_id=u.id
join role r on ur.role_id=r.id
where u.name=?" />
</authentication-provider>
<!-- 配置一个普通的javaBean,此javabean负责从数据库里查询资源和角色的关联关系, -->
<beans:bean id="urlRoleDao" class="dao.UrlRoleDao">
<beans:constructor-arg ref="dataSource" />
<beans:constructor-arg
value="
select rs.value,r.description
from role_resource rr
join resource rs on rr.resource_id=rs.id
join role r on rr.role_id=r.id
" />
</beans:bean>
<!-- 定义自定义过滤器 -->
<beans:bean id="filterInvocationDefinitionSource"
class="filters.CustomObjectDefinitionSource">
<beans:property name="urlRoleDao" ref="urlRoleDao" />
</beans:bean>
<!—实现拦截器,并放入到过滤链中 -->
<beans:bean id="filterSecurityInterceptor" autowire="byType"
class="org.springframework.security.intercept.web.FilterSecurityInterceptor">
<custom-filter before="FILTER_SECURITY_INTERCEPTOR" />
<beans:property name="objectDefinitionSource"
ref="filterInvocationDefinitionSource" />
</beans:bean>
</beans:beans>
全部的web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>SecurityDemo</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/applicationContext-security.xml
</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<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>
<servlet>
<description></description>
<display-name>ToUserHome</display-name>
<servlet-name>toUserHome</servlet-name>
<servlet-class>servlet.ToUserHome</servlet-class>
</servlet>
<servlet>
<description></description>
<display-name>ToAdminHome</display-name>
<servlet-name>ToAdminHome</servlet-name>
<servlet-class>servlet.ToAdminHome</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>toUserHome</servlet-name>
<url-pattern>/toUserHome</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>ToAdminHome</servlet-name>
<url-pattern>/toAdminHome</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
例子
这里我给了这个完整的例子SecurityDemo.zip,把数据库密码改掉,建立上面的表(配置security第一步),
插入一下数据,项目就可以运行了
insert into resource values(1,'url','/*admin*');
insert into resource values(2,'url','/*user*');
insert into role values(1,'管理员','ROLE_ADMIN');
insert into role values(2,'普通用户','ROLE_USER');
insert into user values(1,'admin','admin',1);
insert into user values(2,'user','user',1);
insert into role_resource values(1,1);
insert into role_resource values(2,2);
insert into user_role values(1,1);
insert into user_role values(1,2);
insert into user_role values(2,2);
各页面介绍
login.jsp登录页面,index主页,adminPage.jsp管理员角色主页,需要有管理员权限才能访问userPage.jsp普通用户主页,需要有用户权限才能访问
其中管理员页面和陪同用户页面时只有相应权限的人才能访问。
关于例子里面过滤器实现类的介绍:
代码里有详细注释,先看类级别的注释,最主要的就是那个过滤器类
将SecurityDemo添加到你的项目
如果你有不同的表结构,只需改动第四步和第五步里面的sql语句,但要注意红色字体部分的说明
附
以下都是引用的外部资料
不用重启系统使资源配置生效
目前存在的问题是,系统会在初始化时一次将所有资源加载到内存中,即使在数据库中修改了资源信息,系统也不会再次去从数据库中读取资源信息。这就造成了每次修改完数据库后,都需要重启系统才能时资源配置生效。
解决方案是,如果数据库中的资源出现的变化,需要刷新内存中已加载的资源信息时,使用下面代码:
<%@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.intercept.web.FilterSecurityInterceptor"%>
<%@page import="org.springframework.security.intercept.web.FilterInvocationDefinitionSource"%>
<%
ApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(application);
FactoryBean factoryBean = (FactoryBean) ctx.getBean("&filterInvocationDefinitionSource");
FilterInvocationDefinitionSource fids = (FilterInvocationDefinitionSource) factoryBean.getObject();
FilterSecurityInterceptor filter = (FilterSecurityInterceptor) ctx.getBean("filterSecurityInterceptor");
filter.setObjectDefinitionSource(fids);
%>
<jsp:forward page="/"/>
Spring Security提供了如下内容的控制:
1. url;
2. bean method;
3. http session。
url:可以分为需要权限判断的url,不需要权限判断的url,登录表单url。通过我对spring相关帖子和参考文档的阅读,需要权限判断的url。仅限于做角色判断,就是说判断当前用户是否具有指定的角色。
bean method:Spring支持对Service layer method做权限判断。通过我对spring相关帖子和参考文档的阅读,也仅限于做角色判断。配置方式有2种:
1. 写在Java源代码里面,如:@Secured("ROLE_TELLER")(该方法只有具有TELLER角色的用户能够访问,否则抛出异常);
2. 写在配置文件里面,如:<protect method="set*" access="ROLE_ADMIN" />(该bean的所有set方法,只有具有ADMIN角色的用户能够访问,否则抛出异常)。
http session:控制一个用户名是否能重复登录,以及重复登录次数,并非重试密码次数。
另外,Spring Security还提供了如下一些功能:
1. remember me,记住我;
2. form-login登录控制;
3. 多种身份认证功能;
4. 用户密码加密和“salt”功能;
5. http协议控制;
6. 访问端口控制;
7. Pre-Invocation & After-Invocation。
remember me,记住我:还记得浏览器采用cookie记住用户名和密码自动登录吗?好像就是这个(不知道我理解错了没有,应该没有。只是我不大敢相信)。使用这个功能,开发者在登录页面,使用spring自定义的标签。
form-login登录控制:有些页面不允许匿名访问,那么当匿名访问这些页面的时候,将弹出(或者转到)form-login窗口(或者页面)。这里又牵引出2个问题:1,输入用户名和密码后怎样验证;2,密码是否需要加密,怎么加密。
多种身份认证功能:Spring提供了丰富的用户身份认证功能。身份认证是什么意思?比如您告诉我“我是神仙”。那么我会问您“凭什么证明您是神仙”。这就是身份认证。认证手段一般是保存到数据库表的用户名/密码,usb key,ldap等。一般情况下,我们都使用用户名/密码的。
用户密码加密和“salt”功能:密码采用md5,还是sha加密算法。如果我们对密码加密的时候,不想仅仅对密码加密,还想把用户名和密码放在一起加密做为加密后的密码。那么使用salt吧。salt支持也读取用户的其他属性,不仅是用户名。
http协议控制:哪些url,必须采用https访问呢?哪些url必须采用http访问呢?哪些又两者都可以呢?通过这个配置。
访问端口控制:类似http协议控制,控制url和访问端口之间的关系。
内置截器解释
图1
HttpSessionContextIntegrationFilter:
率先判断用户的session中是否已经存在一个SecurityContext了。如果存在,就把 SecurityContext拿出来,放到SecurityContextHolder中,供Spring Security的其他部分使用。如果不存在,就创建一个SecurityContext出来,还是放到SecurityContextHolder中,供Spring Security的其他部分使用。
用途二,在所有过滤器执行完毕后,清空SecurityContextHolder,因为SecurityContextHolder是基于ThreadLocal的,如果在操作完成后清空ThreadLocal,会受到服务器的线程池机制的影响。
LogoutFilter:
用途是在用户发送注销请求时,销毁用户session,清空SecurityContextHolder,然后重定向到注销成功页面。可以与rememberMe之类的机制结合,在注销的同时清空用户cookie。
AuthenticationProcessingFilter:
处理form登陆的过滤器,与form登陆有关的所有操作都是在此进行的。
默认情况下只处理/j_spring_security_check请求,这个请求应该是用户使用form登陆后的提交地址,
此过滤器执行的基本操作时,通过用户名和密码判断用户是否有效,如果登录成功就跳转到成功页面(可能是登陆之前访问的受保护页面,也可能是默认的成功页面),如果登录失败,就跳转到失败页面。
DefaultLoginPageGeneratingFilter
此过滤器用来生成一个默认的登录页面,默认的访问地址为/spring_security_login,这个默认的登录页面虽然支持用户输入用户名,密码,也支持rememberMe功能,但是因为太难看了,只能是在演示时做个样子,不可能直接用在实际项目中。
BasicProcessingFilter
此过滤器用于进行basic验证,功能与AuthenticationProcessingFilter类似,只是验证的方式不同。
SecurityContextHolderAwareRequestFilter
此过滤器用来包装客户的请求。目的是在原始请求的基础上,为后续程序提供一些额外的数据。比如getRemoteUser()时直接返回当前登陆的用户名之类的。
RememberMeProcessingFilter
此过滤器实现RememberMe功能,当用户cookie中存在rememberMe的标记,此过滤器会根据标记自动实现用户登陆,并创建SecurityContext,授予对应的权限。
AnonymousProcessingFilter
为了保证操作统一性,当用户没有登陆时,默认为用户分配匿名用户的权限。
ExceptionTranslationFilter
此过滤器的作用是处理中FilterSecurityInterceptor抛出的异常,然后将请求重定向到对应页面,或返回对应的响应错误代码。
SessionFixationProtectionFilter
防御session固化攻击。
FilterSecurityInterceptor
用户的权限控制都包含在这个过滤器中。
功能一:如果用户尚未登陆,则抛出AuthenticationCredentialsNotFoundException“尚未认证异常”。
功能二:如果用户已登录,但是没有访问当前资源的权限,则抛出AccessDeniedException“拒绝访问异常”。
功能三:如果用户已登录,也具有访问当前资源的权限,则放行。
注:SecurityContextHolder对象 我们把当前应用程序的当前安全环境的细节存储到它里边了, 它也包含了应用当前使用的主体细节。 默认情况下,SecurityContextHolder使用ThreadLocal存储这些信息, 这意味着,安全环境在同一个线程执行的方法一直是有效的, 即使这个安全环境没有作为一个方法参数传递到那些方法里。 这种情况下使用ThreadLocal是非常安全的, 只要记得在处理完当前主体的请求以后,把这个线程清除就行了。 当然,Spring Security自动帮你管理这一切了, 你就不用担心什么了。
SecurityContext对象,保存Authentication信息,和请求对应的安全信息。
- SecurityDemo_2.04_.zip (3.2 MB)
- 下载次数: 72
相关推荐
总结,SpringSecurity是一个功能强大的安全框架,它为开发者提供了安全Web应用的全套解决方案。通过理解并熟练运用其核心概念和组件,我们可以构建出安全、健壮的应用程序。在学习过程中,分析提供的源代码和示例将...
**Spring Security 概述** Spring Security 是一个强大的且高度可定制的身份验证和访问控制框架,用于保护基于 Java 的应用程序。它提供了全面的安全解决方案,包括Web安全、方法调用安全、API安全等多个方面。...
Spring Security 实践指南 Spring Security 是一个基于 Java 的安全框架,旨在提供身份验证、授权和访问控制等功能。下面是 Spring Security 的主要知识点: 一、身份验证(Authentication) 身份验证是指对用户...
Spring Security是一个功能强大、高度定制的安全框架,它专门用于为基于Spring的应用程序提供安全性解决方案。Spring Security架构的设计初衷是为了解决认证和授权的需求,确保应用程序的安全性。它提供了全面的安全...
Spring Security 是一个强大的安全框架,主要用于Java应用的安全管理,它为Web应用和企业级应用提供了全面的安全服务。这个框架能够处理认证、授权以及各种安全相关的功能,帮助开发者构建安全、可扩展的应用。以下...
【Spring Security 学习总结】 Spring Security 是一个强大的和高度可定制的身份验证和访问控制框架,用于保护基于 Java 的应用程序。本学习总结文档主要针对初学者,旨在剖析一个不安全的应用程序并阐述如何通过 ...
Spring Security 是一个强大的Java安全框架,用于保护基于Spring的应用程序。它提供了全面的安全服务,包括认证、授权、CSRF防护、会话管理等。在深入理解Spring Security之前,我们需要了解几个核心概念: 1. **...
在压缩包文件`spring_gateway_security_webflux`中,可能包含了示例代码或配置文件,用于演示如何在Spring Cloud Gateway中集成Spring Security,实现统一登录认证鉴权。这些资源可以帮助开发者更快地理解和实践上述...
SpringSecurity是Java领域中一款强大的安全框架,主要用于Web应用程序的安全管理。它提供了全面的身份验证、授权、会话管理以及安全相关的功能,可以帮助开发者构建安全的Web应用。在本笔记中,我们将深入探讨Spring...
SpringBoot+SpringSecurity处理Ajax登录请求问题 SpringBoot+SpringSecurity处理Ajax登录请求问题是SpringBoot开发中的一個常见问题,本文将详细介绍如何使用SpringBoot+SpringSecurity处理Ajax登录请求问题。 ...
Spring Security 是一个强大的安全框架,用于为Java应用提供身份验证和授权服务。在这个完整的项目实例中,我们将深入探讨Spring Security的核心概念以及如何将其应用于实际的Web应用程序开发。 首先,我们从用户、...
Spring Security是一个功能强大且高度可定制的身份验证和授权框架,专门用于保护Java应用程序的安全性。它构建在Spring Framework基础之上,提供了全面的安全解决方案,包括身份验证、授权、攻击防护等功能。 Spring...
Spring Security 是一个强大的和高度可定制的身份验证和访问控制框架,广泛用于Java应用程序的安全性管理。这个压缩包包含了Spring Security 4.0.0版本所需的jar包,这是一组核心组件,为构建安全的Web应用提供了...
Spring Security 是一个强大的安全框架,用于为Java应用提供全面的安全管理解决方案。它是Spring生态系统的组成部分,专注于身份验证、授权和访问控制。Spring Security的核心特性包括: 1. **身份验证...
### Spring Security 3.0.1 中文版知识点解析 #### 一、Spring Security 3.0.1 概览 ##### 1.1 Spring Security 是什么? Spring Security 是一个强大的、高度可定制的身份验证和访问控制框架。它提供了许多功能...
总结来说,这个项目演示了如何在SpringBoot环境中,利用SpringSecurity保证安全性,结合WebSocket实现高效、实时的双向通信。这样的架构对于需要实时交互的Web应用,如在线聊天、实时股票交易、游戏等场景非常适用。...
Spring Security3 安全个人总结 Spring Security3 是一个基于 Java 的安全框架,提供了一个灵活的安全机制来保护基于 Spring 的应用程序。在这个总结中,我们将详细介绍 Spring Security3 的安全机制、原理和核心...