-
Spring Security
11個步驟為應(yīng)用程序添加安全防護(hù)
-
歷史與現(xiàn)狀
自2003年出現(xiàn)的Spring擴(kuò)展插件Acegi Security發(fā)展而來。
目前最新版本為3.x,已成為Spring的一部分。
為J2EE企業(yè)應(yīng)用程序提供可靠的安全性服務(wù)。
-
Authentication vs. Authorization
區(qū)分概念驗(yàn)證與授權(quán)
驗(yàn)證
這個用戶是誰?
用戶身份可靠嗎?
授權(quán)
某用戶A是否可以訪問資源R
某用戶A是否可以執(zhí)行M操作
某用戶A是否可以對資源R執(zhí)行M操作
-
SS中的驗(yàn)證特點(diǎn)
支持多種驗(yàn)證方式
支持多種加密格式
支持組件的擴(kuò)展和替換
可以本地化輸出信息
-
SS中的授權(quán)特點(diǎn)
支持多種仲裁方式
支持組件的擴(kuò)展和替換
支持對頁面訪問、方法訪問、對象訪問的授權(quán)。
-
SS核心安全實(shí)現(xiàn)
Web安全
通過配置Servlet Filter激活SS中的過濾器鏈
實(shí)現(xiàn)Session一致性驗(yàn)證
實(shí)現(xiàn)免登陸驗(yàn)證(Remember-Me驗(yàn)證)
提供一系列標(biāo)簽庫進(jìn)行頁面元素的安全控制
方法安全
通過AOP模式實(shí)現(xiàn)安全代理
Web安全與方法安全均可以使用表達(dá)式語言定義訪問規(guī)則
-
配置SS
配置Web.xml,應(yīng)用安全過濾器
配置Spring,驗(yàn)證與授權(quán)部分
在web頁面中獲取用戶身份
在web頁面中應(yīng)用安全標(biāo)簽庫
實(shí)現(xiàn)方法級安全
-
1:配置web.xml
- <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>
- <context-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>classpath:spring.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>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
-
2:Spring配置文件中設(shè)置命名空間
- <?xml version="1.0" encoding="UTF-8"?>
- <beans:beansxmlns="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.0.xsd
- http://www.springframework.org/schema/security
- http://www.springframework.org/schema/security/spring-security-3.0.xsd">
- </beans:beans>
<?xml version="1.0" encoding="UTF-8"?>
<beans:beansxmlns="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.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.0.xsd">
</beans:beans>
-
3:配置最基本的驗(yàn)證與授權(quán)
- <http auto-config="true">
- <intercept-url pattern="/**" access="ROLE_USER" />
- </http>
- <authentication-manager>
- <authentication-provider>
- <user-service>
- <user name="tom" password="123" authorities="ROLE_USER, ROLE_A" />
- <user name="jerry" password="123" authorities="ROLE_USER, ROLE_B" />
- </user-service>
- </authentication-provider>
- </authentication-manager>
<http auto-config="true">
<intercept-url pattern="/**" access="ROLE_USER" />
</http>
<authentication-manager>
<authentication-provider>
<user-service>
<user name="tom" password="123" authorities="ROLE_USER, ROLE_A" />
<user name="jerry" password="123" authorities="ROLE_USER, ROLE_B" />
</user-service>
</authentication-provider>
</authentication-manager>
-
4:通過數(shù)據(jù)庫驗(yàn)證用戶身份
- <authentication-manager>
- <authentication-provider>
- <password-encoder hash=“md5”/>
- <jdbc-user-service data-source-ref="dataSource"/>
- </authentication-provider>
- </authentication-manager>
- 數(shù)據(jù)表結(jié)構(gòu)見SS說明手冊附錄A
<authentication-manager>
<authentication-provider>
<password-encoder hash=“md5”/>
<jdbc-user-service data-source-ref="dataSource"/>
</authentication-provider>
</authentication-manager>
數(shù)據(jù)表結(jié)構(gòu)見SS說明手冊附錄A
-
5:完善web頁面驗(yàn)證規(guī)則
- <http auto-config="true">
- <intercept-url pattern="/js/**" filters="none"/>
- <intercept-url pattern="/css/**" filters="none"/>
- <intercept-url pattern="/images/**" filters="none"/>
- <intercept-url pattern="/a.jsp" access="ROLE_A" />
- <intercept-url pattern="/b.jsp" access="ROLE_B" />
- <intercept-url pattern="/c.jsp" access="ROLE_A, ROLE_B" />
- <intercept-url pattern="/**" access="ROLE_USER" />
- </http>
<http auto-config="true">
<intercept-url pattern="/js/**" filters="none"/>
<intercept-url pattern="/css/**" filters="none"/>
<intercept-url pattern="/images/**" filters="none"/>
<intercept-url pattern="/a.jsp" access="ROLE_A" />
<intercept-url pattern="/b.jsp" access="ROLE_B" />
<intercept-url pattern="/c.jsp" access="ROLE_A, ROLE_B" />
<intercept-url pattern="/**" access="ROLE_USER" />
</http>
-
6:自定義驗(yàn)證配置
- <http auto-config="true">
- <!-- 指定登陸頁面、成功頁面、失敗頁面-->
- <form-login login-page="/login.jsp" default-target-url="/index.jsp" authentication-failure-url="/login.jsp" />
- <!-- 嘗試訪問沒有權(quán)限的頁面時跳轉(zhuǎn)的頁面 -->
- <access-denied-handler error-page="/accessDenied.jsp"/>
- <!-- 使用記住用戶名、密碼功能,指定數(shù)據(jù)源和加密的key -->
- <remember-me data-source-ref="dataSource" />
- <!-- logout頁面,logout后清除session -->
- <logout invalidate-session="true" logout-success-url="/login.jsp" />
- <!-- session 失效后跳轉(zhuǎn)的頁面,最大登陸次數(shù) -->
- <session-management invalid-session-url="/sessionTimeout.htm">
- <concurrency-control max-sessions="1" expired-url="/sessionTimeout.htm" />
- </session-management>
- </http>
- 可以使用SS自帶的登陸頁面作為login.jsp的模板
<http auto-config="true">
<!-- 指定登陸頁面、成功頁面、失敗頁面-->
<form-login login-page="/login.jsp" default-target-url="/index.jsp" authentication-failure-url="/login.jsp" />
<!-- 嘗試訪問沒有權(quán)限的頁面時跳轉(zhuǎn)的頁面 -->
<access-denied-handler error-page="/accessDenied.jsp"/>
<!-- 使用記住用戶名、密碼功能,指定數(shù)據(jù)源和加密的key -->
<remember-me data-source-ref="dataSource" />
<!-- logout頁面,logout后清除session -->
<logout invalidate-session="true" logout-success-url="/login.jsp" />
<!-- session 失效后跳轉(zhuǎn)的頁面,最大登陸次數(shù) -->
<session-management invalid-session-url="/sessionTimeout.htm">
<concurrency-control max-sessions="1" expired-url="/sessionTimeout.htm" />
</session-management>
</http>
可以使用SS自帶的登陸頁面作為login.jsp的模板
-
7:本地化消息輸出
拷貝本地化資源文件后,在配置文件中加載該文件:
- <!-- 加載錯誤信息資源文件 -->
- <beans:bean id="messageSource"
- class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
- <beans:property name="basename" value="classpath:messages"/>
- </beans:bean>
- 資源文件在SS核心包:spring-security-core-3.0.2.RELEASE.jar的orgspringframeworksecurity目錄中
<!-- 加載錯誤信息資源文件 -->
<beans:bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<beans:property name="basename" value="classpath:messages"/>
</beans:bean>
資源文件在SS核心包:spring-security-core-3.0.2.RELEASE.jar的orgspringframeworksecurity目錄中
-
8:在web頁面中獲取用戶信息
- 方式一:Java代碼
- Authentication auth = SecurityContextHolder.getContext().getAuthentication();
- Collection<GrantedAuthority> col = auth.getAuthorities();
- 方式二:標(biāo)簽庫
- <%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
- <sec:authentication property="name“/>
- <sec:authentication property="authorities“/>
方式一:Java代碼
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
Collection<GrantedAuthority> col = auth.getAuthorities();
方式二:標(biāo)簽庫
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
<sec:authentication property="name“/>
<sec:authentication property="authorities“/>
-
9:在web頁面進(jìn)行元素安全控制
- 方式一
- <sec:authorizeifAnyGranted="ROLE_A">
- <a href="a.jsp">你可以訪問a.jsp</a>
- </sec:authorize>
- <sec:authorizeifNotGranted="ROLE_A">
- 你不可以訪問a.jsp
- </sec:authorize>
- 方式二
- <sec:authorizeurl="/a.jsp">
- <a href="a.jsp">你可以訪問a.jsp</a>
- </sec:authorize>
方式一
<sec:authorizeifAnyGranted="ROLE_A">
<a href="a.jsp">你可以訪問a.jsp</a>
</sec:authorize>
<sec:authorizeifNotGranted="ROLE_A">
你不可以訪問a.jsp
</sec:authorize>
方式二
<sec:authorizeurl="/a.jsp">
<a href="a.jsp">你可以訪問a.jsp</a>
</sec:authorize>
-
10:全局方法安全控制
- <global-method-security pre-post-annotations="enabled">
- <protect-pointcut expression="execution(* com.xasxt.*Service.add*(..))" access="ROLE_A"/>
- <protect-pointcut expression="execution(* com.xasxt.*Service.delete*(..))" access="ROLE_B"/>
- </global-method-security>
- 此處使用了AspectJ中常用的切入點(diǎn)表達(dá)式(百度:AspectJ execution)
<global-method-security pre-post-annotations="enabled">
<protect-pointcut expression="execution(* com.xasxt.*Service.add*(..))" access="ROLE_A"/>
<protect-pointcut expression="execution(* com.xasxt.*Service.delete*(..))" access="ROLE_B"/>
</global-method-security>
此處使用了AspectJ中常用的切入點(diǎn)表達(dá)式(百度:AspectJ execution)
-
11:使用注解進(jìn)行方法安全控制
- public class DemoService {
- @PreAuthorize("hasRole('ROLE_A')")
- public void methodA() {
- }
- @PreAuthorize("hasAnyRole('ROLE_A, ROLE_B')")
- public void methodB() {
- }
- }
- hasRole與hasAnyRole為SS通用內(nèi)置表達(dá)式(google : spring security Common Built-In Expressions)
public class DemoService {
@PreAuthorize("hasRole('ROLE_A')")
public void methodA() {
}
@PreAuthorize("hasAnyRole('ROLE_A, ROLE_B')")
public void methodB() {
}
}
hasRole與hasAnyRole為SS通用內(nèi)置表達(dá)式(google : spring security Common Built-In Expressions)
-
12:下一步做什么???
采用更安全的驗(yàn)證方式
采用安全的數(shù)據(jù)傳輸方式
實(shí)現(xiàn)動態(tài)授權(quán)
自定義驗(yàn)證與授權(quán)部件
實(shí)現(xiàn)數(shù)據(jù)級安全