权限控制在网页开发中是很重要的一部分,最基本的就是用form进行账号密码的认证,更复杂的可能控制的粒度会更细一些,spring securty相关的信息在网上可以搜到很多,入门的例程更是多不胜数,但是在我学习了解的过程中,却发现没有一个简单易懂的,给学习之路带来了诸多不便,所以我希望可以用一种更简单的方式来帮助其它想要学习spring securty的人更快的学会使用spring securty。
关于spring securty的原理什么的,网上有很多相关的资料,有些东西我不再具体描述,一些我感觉比较重要的东西,会着重写一些,前面先说一些原理性的东西,后面再进一步把原理转换成实践的小demo,目前最新的版本是4.1,就以4.1版本为例,前面的版本我也不太了解,不过大部分东西都是大同小异的。
spring securty提供多认证方式,这里只讨论用form进行用户名密码验证的方式。
spring securty的使用方式是在web.xml里配置一个filter来拦截想要让spring securty处理的url,在这个filter里维护了一个过滤器链,不同版本里的过滤器链可能会有所有不同。
spring securty 3.0.1里的过滤器链如下:
名称 | 过滤器类 | 命名空间元素或属性 |
---|---|---|
CHANNEL_FILTER | ChannelProcessingFilter | http/intercept-url@requireschannel |
CONCURRENT_SESSION_FILTER | ConcurrentSessionFilter | session-management/concurrency-control |
SECURITY_CONTEXT_FILTER | SecurityContextPersistenceFilter | http |
LOGOUT_FILTER | LogoutFilter | http/logout |
X509_FILTER | X509AuthenticationFilter | http/x509 |
PRE_AUTH_FILTER | AstractPreAuthenticatedProcessingFilter | N/A |
CAS_FILTER | CasAuthenticationFilter | N/A |
FORM_LOGIN_FILTER | UsernamePasswordAuthenticationFilter | http/form-login |
BASIC_AUTH_FILTER | BasicAuthenticationFilter | http/http-basic |
SERVLET_API_SUPPORT_FILTER | SecurityContextHolderAwareFilter | http/@servlet-api-provision |
REMEMBER_ME_FILTER | RememberMeAuthenticationFilter | http/remember-me |
ANONYMOUS_FILTER | SessionManagementFilter | http/anonymous |
SESSION_MANAGEMENT_FILTER | AnonymousAuthenticationFilter | session-management |
EXCEPTION_TRANSLATION_FILTER | ExceptionTranslationFilter | http |
FILTER_SECURITY_INTERCEPTOR | FilterSecurityInterceptor | http |
SWITCH_USER_FILTER | SwitchUserAuthenticationFilter | N/A |
spring securty 4.1.x里的过滤器链如下:
名称 | 过滤器类 | 命名空间元素或属性 |
---|---|---|
CHANNEL_FILTER | ChannelProcessingFilter | http/intercepturl@requires-channel |
SECURITY_CONTEXT_FILTER | SecurityContextPersistenceFilter | http |
CONCURRENT_SESSION_FILTER | ConcurrentSessionFilter | session-management/concurrency-control |
HEADERS_FILTER | HeaderWriterFilter | http/headers |
CSRF_FILTER | CsrfFilter | http/csrf |
LOGOUT_FILTER | LogoutFilter | http/logout |
X509_FILTER | X509AuthenticationFilter | http/x509 |
PRE_AUTH_FILTER | AbstractPreAuthenticatedProcessingFilter | N/A |
CAS_FILTER | CasAuthenticationFilter | N/A |
FORM_LOGIN_FILTER | UsernamePasswordAuthenticaionFilter | http/form-login |
BASIC_AUTH_FILTER | BasicAuthenticationFilter | http/http-basic |
SERVLET_API_SUPPORT_FILTER | SecurityContextHolderAwareRequestFilter | http/@ervet-apiprovision |
JAAS_API_SUPPORT_FILTER | JaasApiIntegrationFilter | http/@jaas-apiprovision |
REMEMBER_ME_FILTER | RememberMeAuthenticationFilter | http/remember-me |
ANONYMOUS_FILTER | AnonymousAuthenticationFilter | http/anonymous |
SESSION_MANAGEMENT_FILTER | SessionManagementFilter | session-management |
EXCEPTION_TRANSLATION_FILTER | ExceptionTranslationFilter | http |
FILTER_SECURITY_INTERCEPTOR | FilterSecurityInterceptor | http |
SWITCH_USER_FILTER | SwitchUserFilter | N/A |
过滤器链里的Filter不能被修改,但是我们可以通过插入自定义的Filter来实现自己想要的功能,当然,更高级的内容会在后面的章节里进行讨论。
现在,我们来做一个最简单的入门Demo,为了尽可能简单,仅仅只引用了spring security。
- spring security所需要的jar包,如果是手动添加,可能要添加一系列的jar包,建议用maven组建项目 ,pom文件如下:
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>pers.homer.test</groupId>
<artifactId>Demo</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>Demo Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>4.1.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>4.1.1.RELEASE</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
<build>
<finalName>Demo</finalName>
</build>
</project>
- 配置web.xml引入spring security
<?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_3_0.xsd"
version="3.0">
<display-name>Archetype Created Web Application</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring-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>
</web-app>
- 配置spring-security.xml文件,让spring 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-3.2.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-4.1.xsd ">
<!-- 不需要进行安全认证的资源 -->
<http pattern="/resources/**" security="none" />
<!-- 资源所需要的权限 -->
<http use-expressions="true" auto-config="true">
<intercept-url pattern="/index.jsp*" access="permitAll" />
<intercept-url pattern="/user.jsp*" access="hasRole('ROLE_USER')" />
<intercept-url pattern="/admin.jsp*" access="hasRole('ROLE_ADMIN')" />
<intercept-url pattern="/**" access="hasRole('ROLE_USER')" />
</http>
<!-- 配置用户和相应的权限 -->
<authentication-manager>
<authentication-provider>
<user-service>
<user name="test" password="test" authorities="ROLE_USER" />
<user name="admin" password="admin" authorities="ROLE_ADMIN" />
</user-service>
</authentication-provider>
</authentication-manager>
</beans:beans>
- 配置部分完成了,通过配置里的内容,我们其实已经可以看出来,我做了三个页面来验证相应的用户权限,最后的工作就是写三个jsp文件,index.jsp , user.jsp ,admin.jsp,这三个jsp文件里的内容可以随便写,我的index.jsp代码如下,其实三个页面就是显示不同的提示,其他两个我们可以自行补充。
<?xml version="1.0" encoding="UTF-8" ?>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Insert title here</title>
</head>
<body>
<div>这是任何人都可以访问的页面</div>
</body>
</html>
到这里,整个demo已经完成了,运行之后,访问相应的页面时,如果没有登录,会自动转到spring security默认的登录页面,登录后即可访问,权限不足时也会有默认的错误提示。
入门的例程做的尽可能的简单,我把spring web MVC的部分也分离了出去,让大家的注意力放在我们关注的地方,后面会逐步讨论更高级的应用。