前言
在Spring MVC的项目中,可以采用Spring 拦截器做权限控制,具体使用方法可以参考另一篇博文《Spring拦截器》。使用Spring 拦截器做权限控制最繁琐的就是需要自己实现用户、角色、权限管理,换到另一个系统又需要重复做一次。庆幸的是Spring Security可以帮我们实现用户、角色、权限管理,让研发人员从这些重复工作中解放出来,简化开发流程。
Spring Security的用户、角色、权限管理可以是基于内存、文件、数据库、LDAP等,但我们常用的还是数据库,这里以mysql数据库为例进行讲解。
现在一般有两种常规方式实现Spring Bean配置:xml配置方式,java配置方式,另外还是Spring Boot简化配置方式,其实可以理解为java方式的升级版。这里以xml配置方式进行讲解,后面有时间再补充一个Spring boot版本的github地址。
Spring Security不仅可以在web层根据链接规则拦截请求做权限控制(类似于spring 拦截器),还可以在其他业务层、dao层等通过注解拦截方法调用做方法级别的权限控制(本质上也可以通过spring aop自己实现)。本次总结主要针对web层的不同链接规则进行不同的权限控制,讲解过程大致分为以下几个步骤:
1、Spring Security相关jar
2、Spring Security xml配置
3、Spring Security数据库认证配置
4、Spring Security相关数据库表创建
5、demo测试
Spring Security相关jar
本次demo搭建,采用的是Spring MVC+Freemaker+Spring Security。为了不占用过多篇幅,这里只列出Spring Security相关jar的Maven配置,其他jar的Maven配置详见文章末尾本次demo搭建的github地址。
<dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> <version> 4.1.0.RELEASE </version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>4.1.0.RELEASE </version> </dependency>
这里使用的Spring Security版本为4.1.0.RELEASE,到目前为止最新的版本为5.0.0,可以根据项目需要进行选择。
2、Spring Security xml配置
Spring Security xml配置,主要配置两个xml文件:web.xml和Spring Security相关bean xml配置文件。首先来看web.xml配置内容,这里只列出Spring Security相关配置,其他配置详见文章末尾github demo地址。
<!-- Spring Secutiry 过滤器链配置 --> <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,否则无法被识别。DelegatingFilterProxy是Spring Security拦截入口,该过滤器链包含多个Filter,每个Filter有各自不同的职责。有些属于固定Filter,每次请求都会执行,有些是可选Filter可以根据Spring Security的配置自由选择需要的Filter。Spring Security支持的Filiter列表以及顺序,可以在SecurityFilters.java中看到:
enum SecurityFilters { FIRST(-2147483648), CHANNEL_FILTER, SECURITY_CONTEXT_FILTER, CONCURRENT_SESSION_FILTER, WEB_ASYNC_MANAGER_FILTER, HEADERS_FILTER, CSRF_FILTER, LOGOUT_FILTER, X509_FILTER, PRE_AUTH_FILTER, CAS_FILTER, FORM_LOGIN_FILTER, OPENID_FILTER, LOGIN_PAGE_FILTER, DIGEST_AUTH_FILTER, BASIC_AUTH_FILTER, REQUEST_CACHE_FILTER, SERVLET_API_SUPPORT_FILTER, JAAS_API_SUPPORT_FILTER, REMEMBER_ME_FILTER, ANONYMOUS_FILTER, SESSION_MANAGEMENT_FILTER, EXCEPTION_TRANSLATION_FILTER, FILTER_SECURITY_INTERCEPTOR, SWITCH_USER_FILTER, LAST(2147483647);
每个常量对应一个Filter,对照关系表为(来自Spring Security官网http://projects.spring.io/spring-security/):
我们可以继承这些Filter实现自己的自定义需求,但首先需要知道这些filter的具体功能是什么,这里只对几个常用的filter进行讲解:
1、SecurityContextPersistenceFilter
用途一,在执行其他过滤器之前,率先判断用户的session中是否已经存在一个SecurityContext了。如果存在,就把SecurityContext拿出来,放到SecurityContextHolder中,供Spring Security的其他部分使用。如果不存在,就创建一个SecurityContext出来,还是放到SecurityContextHolder中,供Spring Security的其他部分使用。有点类似HandlerInterceptor接口的preHandle方法。
用途二,在所有过滤器执行完毕后,清空SecurityContextHolder,因为SecurityContextHolder是基于ThreadLocal的,如果在操作完成后清空ThreadLocal,会受到服务器的线程池机制的影响。有点类似HandlerInterceptor接口的afterCompletion方法。
2、LogoutFilter
只处理注销请求,结合Spring Security http配置进行更改:
<security:logout logout-success-url="/login?logout"/>
用途是在用户发送注销请求时,销毁用户session,清空SecurityContextHolder,
然后重定向到注销成功页面。可以与rememberMe之类的机制结合,在注销的同时清空用户cookie。
3、AbstractPreAuthenticatedProcessingFilter
处理form登陆的过滤器,与form登陆有关的所有操作都是在此进行的。这个请求应该是用户使用form登陆后的提交地址。
此过滤器执行的基本操作时,通过用户名和密码判断用户是否有效,如果登录成功就跳转到成功页面;(可能是登陆之前访问的受保护页面,也可能是默认的成功页面),如果登录失败,就跳转到失败页面。Spring Security http配置方式为:
<security:form-login login-page='/login' default-target-url="/welcome" authentication-failure-url="/login?error" username-parameter="username" password-parameter="password"/>
4、BasicAuthenticationFilter
此过滤器用于进行basic验证,功能与AuthenticationProcessingFilter类似,只是Basic验证方式相比较而言用的不是太多,默认会对密码进行base64加密。Spring Security http配置方式为:
<security:http auto-config="true"> <!-- <security:form-login login-page="/login.jsp"/>--> <security:http-basic/> <security:logout logout-success-url="/login.jsp" invalidate-session="true"/> <security:intercept-url pattern="/login.jsp*" filters="none"/> <security:intercept-url pattern="/admin.jsp*" access="ROLE_ADMIN"/> <security:intercept-url pattern="/index.jsp*" access="ROLE_USER,ROLE_ADMIN"/> <security:intercept-url pattern="/**" access="ROLE_USER,ROLE_ADMIN"/> </security:http>
注意:需要注释掉login-page,因为Basic验证会提供默认登陆页面。
5、SecurityContextHolderAwareRequestFilter
此过滤器用来包装客户的请求。通过查看其源码可以发现其doFilter方法中会创建一个包装类型SecurityContextHolderAwareRequestWrapper对ServletRequest对象进行包装,主要实现了servlet api的一些接口方法isUserInRole、getRemoteUser,为后续程序提供一些额外的数据。即可以从request对象中获取到用户信息。
6、RememberMeAuthenticationFilter
作用为:当用户没有登录而直接访问资源时, 从cookie里找出用户的信息, 如果Spring Security能够识别出用户提供的remember me cookie, 用户将不必填写用户名和密码, 而是直接登录进入系统. 它先分析SecurityContext里有没有Authentication对象. 如果有, 则不做任何操作, 直接跳到下一个过滤器. 如果没有, 则检查request里有没有包含remember-me的cookie信息. 如果有, 则解析出cookie里的验证信息, 判断是否有权限。Spring Security http配置方式为:
<http> ... <remember-me key="myAppKey"/> </http>
7、AnonymousAuthenticationFilter
用于支持Spring Security的匿名访问,适用于 一些公共资源希望所有人都可以看到。对于匿名访问的用户,Spring Security支持为其建立一个匿名的AnonymousAuthenticationToken存放在SecurityContextHolder中,这就是所谓的匿名认证。这样在以后进行权限认证或者做其它操作时我们就不需要再判断SecurityContextHolder中持有的Authentication对象是否为null了,而直接把它当做一个正常的Authentication进行使用就OK了。不现在登录页配置:
<intercept-url pattern="/login.jsp*" access="IS_AUTHENTICATED_ANONYMOUSLY"/> 等同于 <http pattern="/login.jsp" security="none">
自定义匿名配置方式:
<bean id="anonymousAuthFilter" class="org.springframework.security.web.authentication.AnonymousAuthenticationFilter"> <property name="key" value="foobar"/> <property name="userAttribute" value="anonymousUser,ROLE_ANONYMOUS"/> </bean> <bean id="anonymousAuthenticationProvider" class="org.springframework.security.authentication.AnonymousAuthenticationProvider"> <property name="key" value="foobar"/> </bean> security:intercept-url pattern='/common**' access='ROLE_ANONYMOUS'/>
通过上述配置,可以实现对没有权限的用户开发/common**下所有资源。
8、ExceptionTranslationFilter
此过滤器的作用是处理中FilterSecurityInterceptor抛出的异常,然后将请求重定向到对应页面,或返回对应的响应错误代码。
指定不同的异常跳转到不同的页面配置:
<bean id="exceptionTranslationFilter" class="org.springframework.security.web.access.ExceptionTranslationFilter"> <property name="authenticationEntryPoint" ref="authenticationEntryPoint"/> <property name="accessDeniedHandler" ref="accessDeniedHandler"/> </bean> <bean id="authenticationEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint"> <property name="loginFormUrl" value="/login.jsp"/> </bean> <bean id="accessDeniedHandler" class="org.springframework.security.web.access.AccessDeniedHandlerImpl"> <property name="errorPage" value="/accessDenied.htm"/> </bean>
9、FilterSecurityInterceptor
用户的权限控制都包含在这个过滤器中,主要逻辑在父类AbstractSecurityInterceptor中进行处理。
功能一:如果用户尚未登陆,则抛出AuthenticationCredentialsNotFoundException“尚未认证异常”。
功能二:如果用户已登录,但是没有访问当前资源的权限,则抛出AccessDeniedException“拒绝访问异常”。
功能三:如果用户已登录,也具有访问当前资源的权限,则放行。
Spring Security 过滤器链配置
上一节讲述了Spring Security支持的标准Filter列表,Spring Security 过滤器链配置:其实就是把这些Filiter加入到过滤器链中。本次demo中的配置内容:
<security:http auto-config="true"> <!--静态资源和登陆页面不做限制--> <security:intercept-url pattern="/css/**" access="permitAll" /> <security:intercept-url pattern="/login**" access="permitAll" /> <!--只能ADMIN角色访问--> <security:intercept-url pattern="/admin**" access="hasRole('ROLE_ADMIN')" /> <!--通过验证的用户都可以到达这个页面,注意isAuthenticated()带括号--> <security:intercept-url pattern="/welcome**" access="isAuthenticated()" /> <!--其他页面USER角色都可以访问--> <security:intercept-url pattern="/**" access="hasRole('ROLE_USER')" /> <security:form-login login-page='/login' default-target-url="/welcome" authentication-failure-url="/login?error" username-parameter="username" password-parameter="password"/> <!--没有权限错误页面--> <security:access-denied-handler error-page="/nopermit"/> <security:logout logout-success-url="/login?logout"/> <security:csrf /> </security:http>
其他配置很好理解,重点说下auto-config="true"配置,就相当于
<http> <form-login /> <http-basic /> <logout /> </http>
也就是使用了默认的过滤器,如果需要自定义Filter,可以继承上一节中的Filter 自己实现doFilter方法。
Spring Security数据库认证配置
Spring Security认证主要通过AuthenticationManager和AuthenticationProvider实现,AuthenticationProvider有多种实现,本次demo采用默认的数据库认证方式,配置如下:
<security:authentication-manager> <security:authentication-provider user-service-ref='myUserDetailsService'/> </security:authentication-manager>
这里的myUserDetailsService 采用的是默认的JdbcDaoImpl,配置如下:
<bean id="myUserDetailsService" class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl"> <property name="dataSource" ref="dataSource"/> </bean>
JdbcDaoImpl依赖一个数据源“dataSource” bean,本demo采用的是mysql数据源,配置如下:
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql:loadbalance://192.168.148.95:3306/security_test?useUnicode=true&characterEncoding=UTF8"/> <property name="username" value="root"/> <property name="password" value="123456"/> </bean>
Spring Security相关数据库表创建
通过阅读JdbcDaoImpl源码可以发现,Spring Security默认情况下需要在数据库中创建用户表和权限表:
private String authoritiesByUsernameQuery = "select username,authority from authorities where username = ?"; private String usersByUsernameQuery = "select username,password,enabled from users where username = ?";
默认用户表为users,more权限表为:authorities。本次demo的建表语句为:
-- ---------------------------- -- Table structure for `authorities` -- ---------------------------- DROP TABLE IF EXISTS `authorities`; CREATE TABLE `authorities` ( `username` varchar(50) COLLATE utf8_bin NOT NULL, `authority` varchar(50) COLLATE utf8_bin NOT NULL, UNIQUE KEY `ix_auth_username` (`username`,`authority`), CONSTRAINT `fk_authorities_users` FOREIGN KEY (`username`) REFERENCES `users` (`username`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; -- ---------------------------- -- Records of authorities -- ---------------------------- INSERT INTO `authorities` VALUES ('mysql1', 'ROLE_ADD'); INSERT INTO `authorities` VALUES ('mysql1', 'ROLE_ADMIN'); INSERT INTO `authorities` VALUES ('mysql1', 'ROLE_SELECT'); INSERT INTO `authorities` VALUES ('mysql1', 'ROLE_USER'); INSERT INTO `authorities` VALUES ('mysql2', 'ROLE_SELECT'); INSERT INTO `authorities` VALUES ('mysql2', 'ROLE_USER'); -- ---------------------------- -- Table structure for `users` -- ---------------------------- DROP TABLE IF EXISTS `users`; CREATE TABLE `users` ( `username` varchar(50) COLLATE utf8_bin NOT NULL, `password` varchar(50) COLLATE utf8_bin NOT NULL, `enabled` tinyint(1) NOT NULL, PRIMARY KEY (`username`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
从表结构设计不难看出,一个用户可以对应多个角色权限,在为每个新用户分配权限时需要选择多个角色权限,难免有些重复工作。这个问题可以通过开启分组功能解决,如果开启分组功能,同时需要创建分组相关的三张表。一个用户可以对应多个分组,一个分组可以对应多个角色权限。关于分组权限控制这里不再详细讲述。
这里采用的完全是Spring Security默认处理方式,根据自己的实际业务需要可以继承JdbcDaoImpl,重写相关sql语句从自己的用户表、角色权限表获取用户信息。
demo测试
通过上配置即可完成本次demo对Spring Security的引入,最终demo的代码已上传至github:https://github.com/gantianxing/spring-security。下载代码后,采用jdk1.8+tomcat8环境部署,启动程序。访问http://localhost/,默认会跳转到登陆页面:
可以使用msyql1、mysql2、mysql3(密码都是123456)三个账号登陆,进行权限测试。也可以自己在上述users表、authorities表中创建其他账号权限进行测试。
转载请注明出处:
相关推荐
通过这个Spring Security实战例子,你可以深入了解Spring Security的配置、认证和授权机制,以及如何与数据库集成。实践是最好的老师,动手完成这四个小项目将有助于巩固理解,并为你在实际项目中应用Spring ...
SpringSecurity提供了多种认证方式,如基于内存的用户细节服务、数据库连接的用户细节服务等。授权则可以通过访问决策管理器(Access Decision Manager)和权限表达式语言来实现细粒度的权限控制。 2. 注销功能:...
Spring Security是Java平台上的一款强大的安全框架,它为Web应用程序提供了全面的安全管理解决方案。在这个主题中,我们将深入探讨`spring-security-web-3`的源码,理解其核心机制,从而更好地利用这个框架来保护...
Spring Security是Java平台上广泛使用的安全框架,其3.1.0.RELEASE版本是该框架的一个重要里程碑,为开发者提供了全面的安全控制,从Web应用到企业级服务,涵盖了认证、授权和会话管理等多个层面。本文将深入探讨...
《Spring Cloud Security实战详解》 在微服务架构中,安全问题尤为重要,而Spring Cloud Security作为Spring Cloud生态的一部分,为开发者提供了强大的安全管理和身份验证功能。本文将深入探讨Spring Cloud ...
一、Spring Security概述 Spring Security是Spring生态系统的组成部分,主要负责应用程序的安全性,包括身份验证、授权和访问控制。它提供了全面的解决方案,可以防止未经授权的访问,保护敏感数据,防止攻击如XSS...
这三份资料——"实战Spring Security 3.x.pdf"、"Spring Security 3.pdf" 和 "Spring Security使用手册.pdf" 将深入探讨这些概念,并提供实践指导,帮助读者掌握如何在实际项目中应用Spring Security。通过学习这些...
3. **与Hibernate的配合**:Spring Security可以与Hibernate ORM进行深度集成,提供基于数据库的角色和权限管理。 五、实战应用示例 1. **登录页面定制**:展示如何创建自定义登录页面,并将其与Spring Security的...
这个"spring-security-sample"案例代码提供了一个实战教程,帮助开发者理解和应用Spring Security的核心概念。在这个项目中,我们将深入探讨Spring Security的基本配置、认证流程以及授权机制。 首先,Spring ...
7. **实战应用**:对于初学者,可以首先创建一个简单的登录页面,然后配置SpringSecurity来处理登录请求。接着,定义角色和权限,将它们分配给用户。最后,通过注解或配置文件设定哪些URL需要特定角色才能访问。 综...
Spring Security 是一个强大的安全框架,用于为 Java 应用程序提供认证、授权和安全防护功能。这个实战项目针对初学者,旨在帮助理解 Spring Security 的基本概念和配置过程。在这个小型的示例项目中,我们将探讨...
- **定义**: Spring Security 是一款基于 Spring 框架的身份认证(Authentication)与用户授权(Authorization)的安全框架,提供了全面的Web应用程序安全性解决方案。 - **核心技术**: 使用了 Servlet 过滤器、IOC...
在Spring Security 3.1版本中,它提供了一套全面的安全解决方案,涵盖了从用户认证到权限控制等多个层面。本文将深入探讨Spring Security 3.1的核心概念、配置以及实际应用。 1. **核心概念** - **Authentication...
这是一款基于SpringBoot+SpringSecurity的RBAC权限管理系统。原本只想着做成基于SpringSecurity的权限管理系统,但随着功能的增加感觉有些刹不住车了,之后可能会往后台管理系统方向发展。无任何重度依赖,非常适合...
- Spring Security提供身份验证和授权功能,可以使用`@Secured`或`@PreAuthorize`注解进行权限控制。 8. **配置管理** - 应用配置文件`application.properties`或`application.yml`,支持环境变量和命令行参数。 ...
我们可以添加`@EnableWebSecurity`启动Spring Security,并配置权限控制。 10. **部署与运行** 最后,我们可以使用内置的Tomcat服务器通过`mvn spring-boot:run`命令运行应用,或者构建为jar文件部署到云服务器。 ...
Spring Security 框架是一个强大的安全解决方案,专为Java企业级应用设计。在这个经典实例中,我们看到它被应用于一个具体的合同审批系统中。这个系统能够运行,表明它具有完整的功能,包括用户认证、授权以及可能的...
接着,书中详细讲解了Spring Security的身份验证机制,包括基于内存、数据库、 LDAP 的用户认证方式。Spring Security支持多种认证方式,如Basic、Form Login、OAuth2等,这使得开发者能够灵活地处理不同的应用场景...
Spring Security是一个强大的安全框架,用于保护基于Java的应用程序,包括Web应用程序。它提供了一套全面的安全性解决方案,涵盖了认证、授权、会话管理等多个方面。本文将从零开始,逐步解析Spring Security的核心...