通常來講,Web 應用的安全性包括用戶認證(Authentication)和用戶受權(Authorization)兩個部分。用戶認證指的是驗證某個用戶是否爲系統中的合法主體,也就是說用戶可否訪問該系統。用戶受權指的是驗證某個用戶是否有權限執行某個操做。在一個系統中,不一樣用戶所具備的權限是不一樣的。好比對一個文件來講,有的用戶只能進行讀取,而有的用戶能夠進行修改。通常來講,系統會爲不一樣的用戶分配不一樣的角色,而每一個角色則對應一系列的權限。 java
對於上面提到的兩種應用情景,Spring Security 框架都有很好的支持。在用戶認證方面,Spring Security 框架支持主流的認證方式,包括 HTTP 基本認證、HTTP 表單驗證、HTTP 摘要認證、OpenID 和 LDAP 等。在用戶受權方面,Spring Security 提供了基於角色的訪問控制和訪問控制列表(Access Control List,ACL),能夠對應用中的領域對象進行細粒度的控制。 mysql
若Spring Security 整合 CAS單點登陸 ,使用CAS進行認證和獲取受權信息,使用Spring Security驗證權限,則能夠很好的把公共的認證和受權與具體應用剝離開來,同時簡化應用的配置。本文就Spring Security 與 CAS的整合進行說明。 web
[@more @]通常來講,Web 應用的安全性包括用戶認證(Authentication)和用戶受權(Authorization)兩個部分。用戶認證指的是驗證某個用戶是否爲系統中的合法主體,也就是說用戶可否訪問該系統。用戶受權指的是驗證某個用戶是否有權限執行某個操做。在一個系統中,不一樣用戶所具備的權限是不一樣的。好比對一個文件來講,有的用戶只能進行讀取,而有的用戶能夠進行修改。通常來講,系統會爲不一樣的用戶分配不一樣的角色,而每一個角色則對應一系列的權限。 spring
對於上面提到的兩種應用情景,Spring Security 框架都有很好的支持。在用戶認證方面,Spring Security 框架支持主流的認證方式,包括 HTTP 基本認證、HTTP 表單驗證、HTTP 摘要認證、OpenID 和 LDAP 等。在用戶受權方面,Spring Security 提供了基於角色的訪問控制和訪問控制列表(Access Control List,ACL),能夠對應用中的領域對象進行細粒度的控制。 sql
若Spring Security 整合 CAS單點登陸 ,使用CAS進行認證和獲取受權信息,使用Spring Security驗證權限,則能夠很好的把公共的認證和受權與具體應用剝離開來,同時簡化應用的配置。本文就Spring Security 與 CAS的整合進行說明。 數據庫
一 、 基本需求
1. jdk 5.0
2. tomcat 6
3. Spring 3.0.5.RELEASE
4. Spring Security 3.1.0.RELEASE
5. CAS cas-server-3.4.7, cas-client-3.2.0
6. 使用http協議進行傳輸
7. 經過jdbc進行用戶驗證,須要經過casserver提供除登陸用戶名之外的附加信息(用於Spring Security 進行驗證權限) tomcat
2、搭建CAS Server
1. 把從 http://www.jasig.org/cas/download 上下載cas解壓找到 cas-server-3.4.7-releasecas-server-3.4.7modulescas-server-webapp-3.4.7.war , 解壓cas-server-webapp-3.4.7.war ,部署在至tomcat上端口爲 8080的server上,如部署路徑爲 http://localhost:8080/cas 。爲了達到需求目的,咱們主要須要對 /WEB-INF/deployerConfigContext.xml 文件進行修改。 安全
2. 使用jdbc數據源進行用戶認證,須要修改deployerConfigContext.xml 的authenticationHandlers方式
<property name="authenticationHandlers">
<list>
<!--
| This is the authentication handler that authenticates services by means of callback via SSL, thereby validating
| a server side SSL certificate.
+-->
<bean class="org.jasig.cas.authentication.handler.support.HttpBasedServiceCredentialsAuthenticationHandler"
p:httpClient-ref="httpClient" />
<!--
| This is the authentication handler declaration that every CAS deployer will need to change before deploying CAS
| into production. The default SimpleTestUsernamePasswordAuthenticationHandler authenticates UsernamePasswordCredentials
| where the username equals the password. You will need to replace this with an AuthenticationHandler that implements your
| local authentication strategy. You might accomplish this by coding a new such handler and declaring
| edu.someschool.its.cas.MySpecialHandler here, or you might use one of the handlers provided in the adaptors modules.
+-->
//註釋掉,不然只要用戶名和密碼一致的話均可以獲得認證
<!-- bean class="org.jasig.cas.authentication.handler.support.SimpleTestUsernamePasswordAuthenticationHandler" / -->
//數據庫認證方式
<!--DATABASE -- >
<bean class="org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler">
<property name="dataSource" ref="dataSource" />
<property name="sql" value="select password from t_admin_user where login_name=?" />
</bean>
</list>
<property name="authenticationHandlers"> session
<!-- DATABASE 增長數據源配置 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName"><value>com.mysql.jdbc.Driver</value></property>
<property name="url"><value>jdbc:mysql:///cas?useUnicode=true&characterEncoding=utf-8</value></property>
<property name="username"><value>root</value></property>
</bean> app
3.經過casserver提供除登陸用戶名之外的附加信息(用於Spring Security 進行驗證權限),修改/WEB-INF/deployerConfigContext.xml
3.1 修改credentialsToPrincipalResolvers
<property name="credentialsToPrincipalResolvers">
<list>
<bean class="org.jasig.cas.authentication.principal.UsernamePasswordCredentialsToPrincipalResolver" >
<property name="attributeRepository" ref="attributeRepository" /> //增長此屬性,爲認證過的用戶的Principal添加屬性
</bean>
<bean class="org.jasig.cas.authentication.principal.HttpBasedServiceCredentialsToPrincipalResolver" />
</list>
</property>
3.2 修改該文件中默認的 attributeRepositorybean配置
<!-- 使用SingleRowJdbcPersonAttributeDao 獲取更多用戶的信息 -->
<bean id="attributeRepository" class="org.jasig.services.persondir.support.jdbc.SingleRowJdbcPersonAttributeDao">
<constructor-arg index="0" ref="dataSource"/>
<constructor-arg index="1" value="select role_name,group_name from role where login_name = ?"/>
<!--這裏的key需寫username,value對應數據庫用戶名字段 -->
<property name="queryAttributeMapping">
<map>
<entry key="username" value="login_name"/>
</map>
</property>
<!--key對應數據庫字段,value對應客戶端獲取參數 -->
<property name="resultAttributeMapping">
<map>
<entry key="role_name" value="authorities"/> //這個從數據庫中獲取的角色,用於在應用中security的權限驗證
</map>
</property>
</bean>
3.3 修改該文件中最默認的serviceRegistryDao中的屬性所有註釋掉
這個bean中的RegisteredServiceImpl的ignoreAttributes屬性將決定是否添加attributes屬性內容,默認爲false:不添加,只有去掉這個配置,cas server纔會將獲取的用戶的附加屬性添加到認證用的Principal的attributes中去。
<bean id="serviceRegistryDao" class="org.jasig.cas.services.InMemoryServiceRegistryDaoImpl"></bean>
3.4 若採用CAS的 Cas20ServiceTicketValidator 認證,則須要修改WEB-INFviewjspprotocol2.0casServiceValidationSuccess.jsp文件,才能把獲取的屬性傳遞至客戶端
<%@ page session="false" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
<cas:authenticationSuccess>
<cas:user>${fn:escapeXml(assertion.chainedAuthentications[fn:length(assertion.chainedAuthentications)-1].principal.id)}</cas:user>
<c:if test="${not empty pgtIou}">
<cas:proxyGrantingTicket>${pgtIou}</cas:proxyGrantingTicket>
</c:if>
<c:if test="${fn:length(assertion.chainedAuthentications) > 1}">
<cas:proxies>
<c:forEach var="proxy" items="${assertion.chainedAuthentications}" varStatus="loopStatus" begin="0" end="${fn:length(assertion.chainedAuthentications)-2}" step="1">
<cas:proxy>${fn:escapeXml(proxy.principal.id)}</cas:proxy>
</c:forEach>
</cas:proxies>
</c:if>
<!-- 增長以下內容 -->
<c:if test="${fn:length(assertion.chainedAuthentications[fn:length(assertion.chainedAuthentications)-1].principal.attributes)> 0}">
<cas:attributes>
<c:forEach
var="attr"
items="${assertion.chainedAuthentications[fn:length(assertion.chainedAuthentications)-1].principal.attributes}"
varStatus="loopStatus"
begin="0"
end="${fn:length(assertion.chainedAuthentications[fn:length(assertion.chainedAuthentications)-1].principal.attributes)-1}"
step="1">
<cas:${fn:escapeXml(attr.key)}>${fn:escapeXml(attr.value)}</cas:${fn:escapeXml(attr.key)}>
</c:forEach>
</cas:attributes>
</c:if>
</cas:authenticationSuccess>
</cas:serviceResponse>
至此,CAS Server 搭建完畢。
3、搭建CAS Client (即Spring Security)應用
1. CAS Client 下須要把spring-security-cas-3.1.0.M2.jar等Spring Security 相關的jar引入,把cas-client-core-3.2.0.jar引入,用於從cas server上獲取相關認證與受權信息。
2. CAS Client應用的 web.xml , 增長以下
<!-- spring 配置文件-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext-security-ns.xml</param-value>
</context-param>
<!-- spring security filter -->
<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>
<!-- spring 默認偵聽器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
3. spring security 文件的配置 applicationContext-security-ns.xml
<?xml version="1.0"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:security="http://www.springframework.org/schema/security"
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.1.xsd">
<!--
Enable security, let the casAuthenticationEntryPoint handle all intercepted urls.
The CAS_FILTER needs to be in the right position within the filter chain.
-->
<security:http entry-point-ref="casAuthenticationEntryPoint" auto-config="true">
<security:intercept-url pattern="/**" access="ROLE_USER"></security:intercept-url>
<security:custom-filter position="CAS_FILTER" ref="casAuthenticationFilter"></security:custom-filter>
</security:http>
<!--
Required for the casProcessingFilter, so define it explicitly set and
specify an Id Even though the authenticationManager is created by
default when namespace based config is used.
-->
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="casAuthenticationProvider"></security:authentication-provider>
</security:authentication-manager>
<!--
This section is used to configure CAS. The service is the
actual redirect that will be triggered after the CAS login sequence.
-->
<bean id="serviceProperties" class="org.springframework.security.cas.ServiceProperties">
//http://localhost:8088/SpringSecurity 具體應用
// j_spring_cas_security_check spring的虛擬URL,此標誌標識使用 CAS authentication upon return from CAS SSO login.
<property name="service" value="http://localhost:8088/SpringSecurity/j_spring_cas_security_check"></property>
<property name="sendRenew" value="false"></property>
</bean>
<!--
The CAS filter handles the redirect from the CAS server and starts the ticket validation.
-->
<bean id="casAuthenticationFilter" class="org.springframework.security.cas.web.CasAuthenticationFilter">
<property name="authenticationManager" ref="authenticationManager"></property>
</bean>
<!--
The entryPoint intercepts all the CAS authentication requests.
It redirects to the CAS loginUrl for the CAS login page.
-->
<bean id="casAuthenticationEntryPoint" class="org.springframework.security.cas.web.CasAuthenticationEntryPoint">
<property name="loginUrl" value="http://localhost:8080/cas/login"></property> //SSO登陸地址
<property name="serviceProperties" ref="serviceProperties"></property>
</bean>
<!--
Handles the CAS ticket processing.
-->
<bean id="casAuthenticationProvider" class="org.springframework.security.cas.authentication.CasAuthenticationProvider">
<property name="authenticationUserDetailsService" ref="authenticationUserDetailsService"/>
<property name="serviceProperties" ref="serviceProperties"></property>
<property name="ticketValidator">
<bean class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator">
<constructor-arg index="0" value="http://localhost:8080/cas" /> //SSO驗證地址
</bean>
</property>
<property name="key" value="cas"></property>
</bean>
<!-- authorities對應 CAS server的 登陸屬性, 在此設置到spirng security中,用於spring security的驗證 -->
<bean id="authenticationUserDetailsService" class="org.springframework.security.cas.userdetails.GrantedAuthorityFromAssertionAttributesUserDetailsService">
<constructor-arg>
<array>
<value>authorities</value>
</array>
</constructor-arg>
</bean>
</beans>
至此,CAS客戶端搭建完畢。
4、總結
經過上述的配置,則具體應用在使用的時候,用戶認證和受權則無需過問,只需在應用中配置相關的角色訪問權限便可。即,只需對下面的紅色部分進行修改,便可以完成應用的認證和受權工做。大大簡化了應用和認證與受權的剝離工做
<security:http entry-point-ref="casAuthenticationEntryPoint" auto-config="true">
<security:intercept-url pattern="/**" access="ROLE_USER"></security:intercept-url>
<security:custom-filter position="CAS_FILTER" ref="casAuthenticationFilter"></security:custom-filter>
</security:http>
5、擴展
若在同一SSO下有多個應用,同一戶在不一樣應用下有不一樣的角色,則考慮擴展獲取用戶權限的環節;資源和角色在數據庫中進行配置等等。