SpringSecurity能用于保护各种Java应用程序(权限管理框架),但在基于Web的应用程序中使用得最为广泛。
SpringSecurity能以声明的方式来保护Web应用程序的URL访问,只需简单的配置即可实现。
SpringSecurity通过一系列Servlet过滤器为Web应用程序提供了多种安全服务。
HelloWorld!
我们依然从这个经典的程序开始,其实HelloWorld!程序只是学习者直观简单的进入一门语言或工具。我们的这SecurityHelloWrld程序比较一般的HelloWorld程序内容要多一些。我们需要建立两个页面(index.jsp和admin.jsp),index.jsp用于登陆,admin.jsp只有具有ROLE_ADMIN权限的用户才能查看。
我们先想一下需求:
· 防止一个帐户同时在多个机器上登陆
· 帐户只能根据自己的权限操作相应的功能模块
· 帐户只能在页面上看到具有对应权限的数据内容
1.搭建环境
因为我们使用的是Spring-security,所以需要搭建Spring环境。创建一个动态WEB工程(EclipseJavaEE版)。
1).添加jar包: spring.jar、commons-loggin.jar、spring-security-core-2.0.5.jar。
2).WEB文件:
<!-- 搭建Spring --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/classes/applicationContext.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
<!-- 添加Spring-Security过滤器 --> <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> |
看见没,在这用到过滤器代理了!过滤器名称必须指定为”springSecurityFilterChain“,Spring-secrutiy默认为我们提供了一个过滤器。我们也可以编写一个自己的过滤器,然后将它配置为Spring的Bean,Bean的名称必须为 springSecurityFilterChain。
3).applicationContext.xml文件:
<!-- 配置SpringSecurity的http安全服务 --> <sec:http auto-config="true"> <!-- 只有ROLE_ADMIN或ROLE_USER权限用户才能访问index.jsp --> <sec:intercept-url pattern="/index.jsp" access="ROLE_ADMIN,ROLE_USER"/> <!-- 只有ROLE_ADMIN权限用户才能访问admin.jsp --> <sec:intercept-url pattern="/admin.jsp" access="ROLE_ADMIN"/> </sec:http>
<!-- 配置SpringSecutiry的权限信息 --> <sec:authentication-provider> <sec:user-service> <!-- 帐户信息 --> <sec:user password="admin" name="admin" authorities="ROLE_ADMIN"/> <sec:user password="user" name="user" authorities="ROLE_USER"/> </sec:user-service> </sec:authentication-provider>
|
需要为这个spring的配置文件添加:xmlns:sec="http://www.springframework.org/schema/security",具体操作步骤不细说了。
在Spring的配置文件中描述帐户、权限信息,但把这么重要的信息放在这里是不安全的!
2.添加JSP页面
index.jsp,body部分的内容:
<body> <h1>*****INDEX*****</h1> <security:authorize ifAllGranted="ROLE_ADMIN"> <br> <a href="admin.jsp">ADMIN</a> </security:authorize> <br> <a href="logout">LOGOUT</a> </body> |
需要为这个JSP文件导入:<%@ taglib prefix="security"uri="http://www.springframework.org/security/tags"%>。
admin.jsp,body部分的内容:
<body> <h1>*****ADMIN*****</h1> <a href="index.jsp">RETURN</a> </body> |
OK,我们的Spring-securityHelloWorld!程序已经完成了!跑一下,看到这个页面没有?
我们没有为工程添加这们的页面啊!先不管这些,使用我们配置的两个帐户登陆看看功能如何。
3.登出配置
因为我们在页面中添加了登出连接,所以我们添加一个登出配置:
<!-- 配置登出信息 --> <logout logout-url="/logout" logout-success-url="/bye.jsp" invalidate-session="true" /> |
我们添加一个bye.jsp页面,点击logout连接时,就会转到此页面。
4.登陆配置
上面的页面是spring-security自动为我们添加的登陆页面,我们也可以设置自己的登陆页面:
<!-- 配置登陆信息 --> <form-login login-page="/login.jsp" login-processing-url="/login" /> |
login.jsp
<!-- 配置登陆信息 --> <form-login login-page="/login.jsp" login-processing-url="/login" default-target-url="/index.jsp" authentication-failure-url="/loginfail.jsp" always-use-default-target="true"/> |
login-page:登陆页面,这里的login.jsp页面中的表单请求和字段名称必须是spring-security指定的,可以查看spring-security默认为我们提供的页面代码。
login-processing-url:登陆请求处理URL。
default-target-url:登陆成功后,转到的页面。
authentication-failure-url:登陆失败后,转到的页面。
always-use-default-target:一直使用”default-target-url“,这是什么意思?假如我们现在有两个页面可以跳到登陆页面,默认情况下spring-security在登陆成功后会跳转到——跳转登陆页面的页面。如果这个值真,那么登陆成功后会一直跳转到”default-target-url“指定的页面。有些情况下,用户直接进入登陆页面进行登陆,此时登陆成功后会跳转到”default-target-url“指定的页面,如果没有指定这个页面则跳转到index.jsp页面,如果没有index.jsp页面将出错。
问题:
将这么重要的信息放在spring的配置文件中是相当不安全的,Spring-security为们提供了安全的方法,将数据放到数据库中。
三、使用数据库替换配置文件
下面我们就实现将用户的帐户信息存储到数据库中,关于页面的访问权限配置存放到数据库中我们明天再总结。在此我们就不大动干戈去使用Hibernate了,我们使用JDBC。
1.添加JDBC
向Spring添加数据源Bean还记得吗?我们使用的数据源是c3p0。
<context:property-placeholder location="classpath:jdbc.properties" /> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="user" value="${user}" /> <property name="password" value="${password}" /> <property name="driverClass" value="${driverClass}" /> <property name="jdbcUrl" value="${jdbcUrl}" />
<property name="minPoolSize" value="5" /> <property name="initialPoolSize" value="3" /> <property name="maxPoolSize" value="10" /> <property name="acquireIncrement" value="2" /> </bean> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.simple.SimpleJdbcTemplate"> <constructor-arg ref="dataSource"/> </bean> |
2.建数据库和数据表
用户表与角色表是什么关系?当前是多对多喽!因此我们需要三个表:
1).user(用户表)
2).role(角色表)
3).user_role(中间表)
3.从数据库中读取权限信息
我们的数据源、jdbcTemplate和数据库已经建好了,接下来就是让spring-security可以读取到数据库中的信息,根据这些信息判断用户输入的登陆信息是否正确以及用户所具有的权限。
1).要想spring-security可以读取到数据库中的信息,我们必须编写一个实现了UserDetailsService接口的类:
package cn.itcast.cc.spring.security;
import java.util.List; import java.util.Map; import javax.annotation.Resource; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; import org.springframework.security.GrantedAuthority; import org.springframework.security.GrantedAuthorityImpl; import org.springframework.security.userdetails.User; import org.springframework.security.userdetails.UserDetails; import org.springframework.security.userdetails.UserDetailsService; import org.springframework.security.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Component;
@Component("userDetailsService") public class UserDetailsServiceImpl implements UserDetailsService {
@Resource private SimpleJdbcTemplate jdbcTemplate = null;
@Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException { // 根据用户名获取帐户和权限信息 String sql = "SELECT username,password,status,name rname" + " FROM user u,role r,user_role ur" + " WHERE u.id=ur.user_id AND r.id=ur.role_id AND username=?"; // 如果一个用户具有多个权限,连接查询会返回一个List List list = this.jdbcTemplate.queryForList(sql, new Object[] { username });
// 取出帐户和权限信息填充到User中返回 if (list == null || list.size() <= 0) // spring-security定义的异常 throw new UsernameNotFoundException("用户不存在!"); // 如果用户存在 Map<String, Object> map = (Map<String, Object>) list.get(0); // 密码 String password = (String) map.get("password"); // 帐户是否可用 boolean enabled = ((Integer) map.get("status") == 1); // 帐户所具有的权限 GrantedAuthority[] gas = new GrantedAuthority[list.size()]; for (int i = 0; i < gas.length; i++) { Map<String, Object> temp = (Map<String, Object>) list.get(i); gas[i] = new GrantedAuthorityImpl((String) temp.get("rname")); } // spring-security提供的类 User user = new User(username, password, enabled, true, true, true, gas); return user; } } |
一定要记住实现的是UserDetailsService 接口,在spring-security帮助手册中应该有。佟佟今天领着大家看着源码,下着断点,找到了这个接口。
2).将applicationContext.xml文件中的”<!-- 配置SpringSecutiry的权限信息 -->“部分,全部替换为:
<authentication-provider user-service-ref="userDetailsService" /> |
********************************************************************************************************************************************************************
1.applicationContext.xml
将昨天applicationContext.xml“配置SpringSecurity的http安全服务”部分的内容替换为:
<sec:http auto-config="true" session-fixation-protection="none" /> <bean class="org.springframework.security.intercept.web.FilterSecurityInterceptor" autowire="byType"> <sec:custom-filter before="AUTHENTICATION_PROCESSING_FILTER"/> <property name="objectDefinitionSource" ref="objectDefinitionSource"/> </bean> |
这里的objectDefinitionSource是下边的类,cutom-filter是在调用AUTHENTICATION_PROCESSING_FILTER过滤器之前调用FilterSecurityInterceptor。
2.添加数据表
resc表与role表是多对多关系。
1).resc
2).resc_role
3.相关类
要让spring-security可以从数据库中获取相关资源信息,我们必须编写一个实现FactoryBean接口的类。
package cn.itcast.cc.spring.security;
import java.util.LinkedHashMap; import java.util.Map; import javax.annotation.Resource; import org.springframework.beans.factory.FactoryBean; import org.springframework.security.ConfigAttributeDefinition; import org.springframework.security.ConfigAttributeEditor; import org.springframework.security.intercept.web.DefaultFilterInvocationDefinitionSource; import org.springframework.security.intercept.web.RequestKey; import org.springframework.security.util.AntUrlPathMatcher; import org.springframework.security.util.UrlMatcher; import org.springframework.stereotype.Component;
@Component("objectDefinitionSource") public class DefaultFilterInvocationDefinitionSourceImpl implements FactoryBean {
@Resource ResourceDetailsService resourceDetailsService;
private UrlMatcher getUrlMatcher() { UrlMatcher urlMatcher = new AntUrlPathMatcher(); return urlMatcher; }
@Override public Object getObject() throws Exception { UrlMatcher urlMatcher = this.getUrlMatcher(); // 获取数据Map Map<String, String> srcMap = resourceDetailsService.buildRequestMap(); LinkedHashMap<RequestKey, Object> requestMap = new LinkedHashMap<RequestKey, Object>(); ConfigAttributeEditor editor = new ConfigAttributeEditor(); // 转换数据Map for (Map.Entry<String, String> entry : srcMap.entrySet()) { String url = entry.getKey(); String roles = entry.getValue(); if (roles != null) { editor.setAsText(roles); requestMap.put(new RequestKey(url), editor.getValue()); } else { requestMap.put(new RequestKey(url), ConfigAttributeDefinition.NO_ATTRIBUTES); } } // 生成并返回对象 return new DefaultFilterInvocationDefinitionSource(urlMatcher, requestMap); }
@Override public Class getObjectType() { return null; }
@Override public boolean isSingleton() { return false; }
} |
其中ResourceDetailsService接口的实现类如下:
package cn.itcast.cc.spring.security;
import java.util.HashMap; import java.util.List; import java.util.Map; import javax.annotation.Resource; import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; import org.springframework.stereotype.Component;
@Component("userDetailsService") public class ResourceDetailsServiceImpl implements ResourceDetailsService {
@Resource private SimpleJdbcTemplate jdbcTemplate; @Override public Map<String, String> buildRequestMap() { // 注意:这里需要使用左外连接查询,是因为有些页面没有指定role。 // 即,任何权限都不可以访问的页面! String sql = "SELECT res_string as url,r.name as role " + "FROME resc LEFT JOIN resc_role rr ON rr.resc_id = resc.id " + "LEFT JOIN role r ON rr.role_id = r.id"; List<Map<String, Object>> results = this.jdbcTemplate.queryForList(sql); Map<String, String> srcMap = new HashMap<String, String>(); // 将查询后的数据拼接并放入到Map中 for(Map<String,Object> val:results){ String url = (String) val.get("url"); String role = (String) val.get("role"); if(srcMap.containsKey(url)){ role = srcMap.get(url) + "," + role; } srcMap.put(url, role); } return srcMap; } } |
相关推荐
在这个"Spring Security 入门demo"中,我们将会探讨一系列关键概念和功能,通过提供的压缩包文件,我们可以看到不同方面的实现示例。 1. **Spring Security RESTful服务**: - `spring-security-rest-full` 模块...
**Spring Security 入门实例详解** Spring Security 是一个强大的安全框架,用于保护基于 Java 的 Web 应用程序。它提供了一套完整的访问控制和身份验证机制,帮助开发者处理应用程序的安全需求。本教程将引导你...
在这个入门Demo实例中,我们将探讨如何配置和使用Spring Security来保护我们的Java应用。教程链接提及的CSDN博客文章提供了详细的步骤,指导我们逐步创建一个基本的Spring Security应用。 首先,我们需要在项目中...
在 `HelloSpringSecurity` 文件中,你可能看到以下关键代码: - **WebSecurityConfigurerAdapter** 类:这是 Spring Security 提供的配置适配器,可以覆盖其方法来定制安全规则。 - `configure(HttpSecurity http)...
以上章节构建了一个全面的Spring Security入门知识体系,为学习者提供了深入理解Spring Security的路径。从基础的介绍到具体的设计与应用,从服务层到Web层的安全配置,再到与其它技术的整合,本书内容丰富,覆盖了...
在这个"springboot+springsecurity入门"项目中,我们将关注如何将这两个框架结合使用,实现一个自定义表单登录的功能。自定义表单登录意味着我们可以根据应用需求设计登录界面,并且处理用户提交的登录信息。 1. ...
"HAP框架-SpringSecurity入门手册.docx"应包含了详细的步骤和示例,指导开发者如何在HAP框架下配置和使用SpringSecurity。建议仔细阅读并结合实际项目进行实践,以加深理解和掌握。 总的来说,SpringSecurity在HAP...
通过以上步骤,我们可以构建一个基本的SpringBoot + Spring Security入门程序,实现用户登录和自动登录功能。这个程序结合了数据库集成、安全配置以及IDEA的使用,为开发者提供了一个完整的实践案例。在实际开发中,...
Spring Security 是一个强大的安全框架,用于为Java应用提供身份验证和授权服务。在这个完整的项目实例中,我们将深入探讨Spring Security的核心概念以及如何将其应用于实际的Web应用程序开发。 首先,我们从用户、...
springsecurity入门笔记+教程
本手册是关于HAP框架中Spring Security的入门指南,由Chenxinkai在2016年7月13日创建,并于2016年7月24日进行了最后更新。该文档的参考编号为Hap框架 Spring Security 使用,版本号为1.0。本手册仅供内部使用,未经...
### Spring Security 全套入门到项目实战课程知识点详解 #### 一、Spring Security 概述 **1.1 Spring Security 介绍** - **定义**: Spring Security 是一款基于 Spring 框架的身份认证(Authentication)与用户...
在这个入门程序中,我们将深入理解如何将SpringBoot与Spring Security整合,以实现用户身份验证和授权功能,并通过自动登录功能提升用户体验。 Spring Security的核心功能包括身份验证(Authentication)和授权...
在这个"Spring_Security入门demo(maven项目)"中,我们将探讨如何搭建一个基本的Spring Security环境,理解其核心概念,并通过实际操作来熟悉它的配置和功能。 **1. Maven项目介绍** Maven 是一个项目管理和综合...
Spring Security 是一个强大的安全框架,用于为 Java 应用程序提供认证、授权和安全防护功能。这个实战项目针对初学者,旨在帮助理解 Spring Security 的基本概念和配置过程。在这个小型的示例项目中,我们将探讨...
在这个入门总结中,我们将探讨如何为新手配置和使用SpringSecurity。 首先,SpringBoot 已经为我们提供了SpringSecurity的自动配置。在默认情况下,当我们启动应用时,控制台会输出一个UUID值,这个值用于默认账户...
hello大家好,这里是X,今天这篇博文带来的是SpringBoot安全管理:SpringSecurity,讲到安全管理,不得不说几乎所有的大型项目开发必备之一,而且有了它,对项目的安全也起到了非常大的效果,可以说是项目搭建的必备...
"级别的项目通常是编程初学者的第一步,而“入门”则表明这适用于那些初次接触Spring Security的人。标签中的“spring security”是核心关键词,指的是这个项目将围绕Spring Security框架进行,帮助新手了解其工作...
本教程是基于Mossle平台整理的Spring Security入门资料,旨在帮助初学者快速掌握这一关键的安全技术。 首先,我们要理解Spring Security的核心概念。**认证**是验证用户身份的过程,通常涉及用户名和密码的输入。**...
在 SpringSecurity电子书中,作者Ben Alex和Luke Taylor提供了对Spring Security的全面介绍,涵盖了从基本概念到高级特性以及如何配置和使用Spring Security的详细指南。 知识点一:Spring Security基础 1. Spring ...