單點登陸(Single Sign On),簡稱爲 SSO,是目前比較流行的企業業務整合的解決方案之一。SSO的定義是在多個應用系統中,用戶只須要登陸一次就能夠訪問全部相互信任的應用系統css
Centos7安裝cas系統html
(1) 上傳cas.war到Centos機器的tomcat/webapps目錄下前端
(2) 端口修改java
vim /usr/local/tomcat/apache-tomcat-7.0.52/conf/web.xml
vim /usr/local/tomcat/apache-tomcat-7.0.52/webapps/cas/WEB-INF/cas.properties
(3) 去除https認證mysql
1) 修改cas的WEB-INF/deployerConfigContext.xmlweb
vim /usr/local/tomcat/apache-tomcat-7.0.52/webapps/cas/WEB-INF/deployerConfigContext.xml
2) 修改cas的/WEB-INF/spring-configuration/ticketGrantingTicketCookieGenerator.xmlspring
參數p:cookieSecure="true",同理爲HTTPS驗證相關,TRUE爲採用HTTPS驗證,FALSE爲不採用https驗證。sql
參數p:cookieMaxAge="-1",是COOKIE的最大生命週期,-1爲無生命週期,即只在當前打開的窗口有效,關閉或從新打開其它窗口,仍會要求驗證。能夠根據須要修改成大於0的數字,好比3600等,意思是在3600秒內,打開任意窗口,都不須要驗證express
vim /usr/local/tomcat/apache-tomcat-7.0.52/webapps/cas/WEB-INF/spring-configuration/ticketGrantingTicketCookieGenerator.xml
3) 修改cas的WEB-INF/spring-configuration/warnCookieGenerator.xmlapache
vim /usr/local/tomcat/apache-tomcat-7.0.52/webapps/cas/WEB-INF/spring-configuration/warnCookieGenerator.xml
(4) cas認證數據源配置
1) 修改cas服務端中web-inf下deployerConfigContext.xml ,添加以下配置
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" p:driverClass="com.mysql.jdbc.Driver" p:jdbcUrl="jdbc:mysql://127.0.0.1:3306/db?characterEncoding=utf8" p:user="user" p:password="password" /> <bean id="passwordEncoder" class="org.jasig.cas.authentication.handler.DefaultPasswordEncoder" c:encodingAlgorithm="MD5" p:characterEncoding="UTF-8" /> <bean id="dbAuthHandler" class="org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler" p:dataSource-ref="dataSource" p:sql="select password from tb_user where username = ?" p:passwordEncoder-ref="passwordEncoder"/>
2)
註釋:<entry key-ref="primaryAuthenticationHandler" value-ref="primaryPrincipalResolver" /> 添加:<entry key-ref="dbAuthHandler" value-ref="primaryPrincipalResolver"/> 搜索定位:在瀏覽模式下:/<entry key-ref="primaryAuthenticationHandler" value-ref="primaryPrincipalResolver" />
3) 導入jar包
cp -r c3p0-0.9.1.2.jar /usr/local/tomcat/apache-tomcat-7.0.52/webapps/cas/WEB-INF/lib cp -r cas-server-support-jdbc-4.0.0.jar /usr/local/tomcat/apache-tomcat-7.0.52/webapps/cas/WEB-INF/lib cp -r mysql-connector-java-5.1.32.jar /usr/local/tomcat/apache-tomcat-7.0.52/webapps/cas/WEB-INF/lib
(5) 替換cas登陸頁面
1) 將css js等文件夾拷貝到 cas目錄下
2) 將工程登陸頁拷貝到cas系統下WEB-INF\view\jsp\default\ui 目錄下,並重命名爲casLoginView.jsp(先重命名cas系統原casLoginView.jsp)
3) 添加指令
<%@ page pageEncoding="UTF-8" %> <%@ page contentType="text/html; charset=UTF-8" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %> <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %> <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
4) 修改form標籤
<form:form method="post" id="fm1" commandName="${commandName}" htmlEscape="true" class="sui-form"> ...... </form:form>
5) 修改登陸框
<form:input id="username" tabindex="1" accesskey="${userNameAccessKey}" path="username" autocomplete="off" htmlEscape="true" placeholder="郵箱/用戶名/手機號" class="span2 input-xfat" /> <form:password id="password" tabindex="2" path="password" accesskey="${passwordAccessKey}" htmlEscape="true" autocomplete="off" placeholder="請輸入密碼" class="span2 input-xfat" />
6) 修改登陸按鈕
<input type="hidden" name="lt" value="${loginTicket}" />
<input type="hidden" name="execution" value="${flowExecutionKey}" />
<input type="hidden" name="_eventId" value="submit" />
<input class="sui-btn btn-block btn-xlarge btn-danger" accesskey="l" value="登錄" type="submit" />
7) 錯誤提示,在form內表單添加
<form:errors path="*" id="msg" cssClass="errors" element="div" htmlEscape="false" />
8) 修改錯誤提示
vim /usr/local/tomcat/apache-tomcat-7.0.52/webapps/cas/WEB-INF/cas-servlet.xml
9) 在messages_zh_CN.properties添加如下內容
vim /usr/local/tomcat/apache-tomcat-7.0.52/webapps/cas/WEB-INF/classes/messages_zh_CN.properties
authenticationFailure.AccountNotFoundException=\u7528\u6237\u4E0D\u5B58\u5728. authenticationFailure.FailedLoginException=\u5BC6\u7801\u9519\u8BEF.
spring-security整合cas
(1) 添加依賴
<!-- spring安全框架 --> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <scope>provided</scope> </dependency>
<!-- cas --> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-cas</artifactId> </dependency> <dependency> <groupId>org.jasig.cas.client</groupId> <artifactId>cas-client-core</artifactId> <exclusions> <exclusion> <groupId>org.slf4j</groupId> <artifactId>log4j-over-slf4j</artifactId> </exclusion> </exclusions> </dependency>
(2) 受權認證類
import java.util.ArrayList; import java.util.List; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; public class UserDetailServiceImpl implements UserDetailsService { @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { System.out.println("UserDetailsServiceImpl : " + username); // 角色受權 List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>(); GrantedAuthority authority = new SimpleGrantedAuthority("ROLE_USER"); authorities.add(authority); return new User(username, "", authorities); } }
(3) spring-security.xml
<?xml version="1.0" encoding="UTF-8"?> <beans:beans xmlns="http://www.springframework.org/schema/security" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" xmlns:context="http://www.springframework.org/schema/context" 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.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd"> <context:property-placeholder location="classpath:properties/*.properties" /> <!-- 如下頁面不被攔截 --> <http pattern="/register.html" security="none"></http> <http pattern="/user/add.do" security="none"></http><!-- 放行註冊請求 --> <http pattern="/user/sendVCode.do" security="none"></http><!-- 放行註冊請求 --> <http pattern="/css/**" security="none"></http> <http pattern="/img/**" security="none"></http> <http pattern="/js/**" security="none"></http> <http pattern="/plugins/**" security="none"></http>
<!-- (1)
此配置是跳過security校驗,因此:SecurityContextHolder.getContext().getAuthentication() = null
<http pattern="/cart/*.do" security="none"></http> --> <!-- spring-security整合CAS單點登陸系統 --> <!-- entry-point-ref 入口點引用 --> <http use-expressions="false" entry-point-ref="casProcessingFilterEntryPoint"> <!-- (2)
注入匿名訪問的角色 -->
<intercept-url pattern="/cart/*.do" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<intercept-url pattern="/**" access="ROLE_USER" /> <csrf disabled="true" /> <!-- custom-filter爲過濾器, position 表示將過濾器放在指定的位置上,before表示放在指定位置以前 ,after表示放在指定的位置以後 --> <custom-filter ref="casAuthenticationFilter" position="CAS_FILTER" /> <custom-filter ref="requestSingleLogoutFilter" before="LOGOUT_FILTER" /> <custom-filter ref="singleLogoutFilter" before="CAS_FILTER" /> </http> <!-- CAS入口點 開始 --> <beans:bean id="casProcessingFilterEntryPoint" class="org.springframework.security.cas.web.CasAuthenticationEntryPoint"> <!-- 單點登陸服務器登陸URL --> <beans:property name="loginUrl" value="http://127.0.0.1:8080/cas/login" /> <beans:property name="serviceProperties" ref="serviceProperties" /> </beans:bean> <beans:bean id="serviceProperties" class="org.springframework.security.cas.ServiceProperties"> <!--service 配置自身工程的根地址+/login/cas --> <beans:property name="service" value="http://localhost:9107/login/cas" />
</beans:bean> <!-- CAS入口點 結束 --> <!-- 認證過濾器 開始 --> <beans:bean id="casAuthenticationFilter" class="org.springframework.security.cas.web.CasAuthenticationFilter"> <beans:property name="authenticationManager" ref="authenticationManager" /> </beans:bean> <!-- 認證管理器 --> <authentication-manager alias="authenticationManager"> <authentication-provider ref="casAuthenticationProvider"> </authentication-provider> </authentication-manager> <!-- 認證提供者 --> <beans:bean id="casAuthenticationProvider" class="org.springframework.security.cas.authentication.CasAuthenticationProvider"> <beans:property name="authenticationUserDetailsService"> <beans:bean class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper"> <beans:constructor-arg ref="userDetailService" /> </beans:bean> </beans:property> <beans:property name="serviceProperties" ref="serviceProperties" /> <!-- ticketValidator 爲票據驗證器 --> <beans:property name="ticketValidator"> <beans:bean class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator"> <beans:constructor-arg index="0" value="http://127.0.0.1:8080/cas" />
</beans:bean> </beans:property> <beans:property name="key" value="an_id_for_this_auth_provider_only" /> </beans:bean> <!-- 認證類 --> <beans:bean id="userDetailService" class="com.xxx.user.service.impl.UserDetailServiceImpl" /> <!-- 認證過濾器 結束 --> <!-- 單點登出 開始 --> <beans:bean id="singleLogoutFilter" class="org.jasig.cas.client.session.SingleSignOutFilter" /> <beans:bean id="requestSingleLogoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter">
<!-- 退出登陸後跳轉的路徑 --> <beans:constructor-arg value="http://127.0.0.1:8080/cas/logout?service=http://localhost:9107" /> <beans:constructor-arg> <beans:bean class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler" /> </beans:constructor-arg> <beans:property name="filterProcessesUrl" value="/logout/cas" /> </beans:bean> <!-- 單點登出 結束 --> </beans:beans>
(4) web.xml
<welcome-file-list> <welcome-file>home-index.html</welcome-file> </welcome-file-list> <!-- post亂碼過濾器 --> <filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- 前端控制器 --> <servlet> <servlet-name>xxx-user-web</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- contextConfigLocation不是必須的, 若是不配置contextConfigLocation, springmvc的配置文件默認在:WEB-INF/servlet的name+"-servlet.xml" --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring/springmvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>xxx-user-web</servlet-name> <!-- 攔截全部請求jsp除外 --> <url-pattern>*.do</url-pattern> </servlet-mapping> <!-- spring安全框架 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring/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>
(5) 頁面登出代碼
<span class="safe"> <a href="/logout/cas">退出登陸 </a></span>
(6) 獲取登陸名
@RestController public class UserController { @RequestMapping("/findLoginUser") public void findLoginUser(){ String name = SecurityContextHolder.getContext().getAuthentication().getName(); System.out.println(name); } }