什么是单点登录?
单点登录(Single Sign On),简称为 SSO,是目前比较流行的企业业务整合的解决方案之一。现今开发的项目大多数都存在诸多个子系统子模块,而这些子模块子系统大多数都是分别部署在不同的服务器上,传统的用户登录session保存用户信息只能存储在一个服务器上,无法解决多模块多服务的问题。SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。
单点登出
什么是CAS:
CAS 是 Yale 大学发起的一个开源项目,旨在为 Web 应用系统提供一种可靠的单点登录方法,CAS 在 2004 年 12 月正式成为 JA-SIG 的一个项目。CAS 具有以下特点:
- 开源的企业级单点登录解决方案。
- CAS Server 为需要独立部署的 Web 应用。
- CAS Client 支持非常多的客户端(这里指单点登录系统中的各个 Web 应用),包括 Java, .Net, PHP, Perl, Apache, uPortal, Ruby 等。
从结构上看,CAS 包含两个部分: CAS Server 和 CAS Client。CAS Server 需要独立部署,主要负责对用户的认证工作;CAS Client 负责处理对客户端受保护资源的访问请求,需要登录时,重定向到 CAS Server。
SSO单点登陆访问流程:
-
SSO客户端发送请求访问应用系统提供的服务资源。
-
SSO客户端会重定向用户请求到SSO服务器。
-
用户身份认证。
-
SSO服务器会产生一个随机的Service Ticket。
-
SSO服务器验证票据Service Ticket的合法性,验证通过后,允许客户端访问服务。
-
SSO服务器验证票据通过后,传输用户认证结果信息给客户端。
CAS服务端的配置:
修改端口:打开tomcat 目录 conf\server.xml,找到下图位置将端口号修改为指定的端口号即可。
打开cas/WEB-INF/cas.properties
去除https认证:
CAS默认使用的是HTTPS协议,如果使用HTTPS协议需要SSL安全证书。开发测试阶段使用安全要求不高免费的http协议即可。
- 打开cas的WEB-INF/deployerConfigContext.xml文件找到
<bean class="org.jasig.cas.authentication.handler.support.HttpBasedServiceCredentialsAuthenticationHandler"
p:httpClient-ref="httpClient"/>
//增加一条参数:p:requireSecure="false" requireSecure属性意思为是否需要安全验证(https)
- 打开cas的/WEB-INF/spring-configuration/ticketGrantingTicketCookieGenerator.xml找到
<bean id="ticketGrantingTicketCookieGenerator" class="org.jasig.cas.web.support.CookieRetrievingCookieGenerator"
p:cookieSecure="true"
p:cookieMaxAge="-1"
p:cookieName="CASTGC"
p:cookiePath="/cas" />
//讲p:cookieSecure="true" 改为false TRUE为采用HTTPS验证,FALSE为不采用https验证。
//参数p:cookieMaxAge="-1",是COOKIE的最大生命周期,-1为无生命周期,即为只在当前窗口有效
设置为3600 则在3600秒之内可以任意打开窗口,都不需要验证
- 打开cas的WEB-INF/spring-configuration/warnCookieGenerator.xml文件 找到
<bean id="warnCookieGenerator" class="org.jasig.cas.web.support.CookieRetrievingCookieGenerator"
p:cookieSecure="true"
p:cookieMaxAge="-1"
p:cookieName="CASPRIVACY"
p:cookiePath="/cas" />
//同理将cookieSecure的值改为false cookieMaxAge改为指定的时间即可
- 打开cas-servlet.xml
<bean id="logoutAction" class="org.jasig.cas.web.flow.LogoutAction"
p:servicesManager-ref="servicesManager"
p:followServiceRedirects="${cas.logout.followServiceRedirects:true}"/>
cas.logout.followServiceRedirects 默认的为false 修改为true 允许重定向
在使用单点登陆系统的项目中加入配置web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<!-- 用于单点退出,该过滤器用于实现单点登出功能,可选配置 -->
<listener>
<listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
</listener>
<!-- 该过滤器用于实现单点登出功能,可选配置。 -->
<filter>
<filter-name>CAS Single Sign Out Filter</filter-name>
<filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CAS Single Sign Out Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 该过滤器负责用户的认证工作,必须启用它 -->
<filter>
<filter-name>CASFilter</filter-name> <filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
<init-param>
<param-name>casServerLoginUrl</param-name>
<param-value>http://localhost:9100/cas/login</param-value>
<!--这里的server是服务端的IP -->
</init-param>
<init-param>
<param-name>serverName</param-name>
<param-value>http://localhost:9001</param-value>
//使用单点登陆系统的服务IP
</init-param>
</filter>
<filter-mapping>
<filter-name>CASFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 该过滤器负责对Ticket的校验工作,必须启用它 -->
<filter>
<filter-name>CAS Validation Filter</filter-name>
<filter-class> org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter</filter-class>
<init-param>
<param-name>casServerUrlPrefix</param-name>
<param-value>http://localhost:9100/cas</param-value>
</init-param>
<init-param>
<param-name>serverName</param-name>
<param-value>http://localhost:9001</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CAS Validation Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 该过滤器负责实现HttpServletRequest请求的包裹, 比如允许开发者通过HttpServletRequest的getRemoteUser()方法获得SSO登录用户的登录名,可选配置。 -->
<filter>
<filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
<filter-class>
org.jasig.cas.client.util.HttpServletRequestWrapperFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 该过滤器使得开发者可以通过org.jasig.cas.client.util.AssertionHolder来获取用户的登录名。 比如AssertionHolder.getAssertion().getPrincipal().getName()。 -->
<filter>
<filter-name>CAS Assertion Thread Local Filter</filter-name> <filter-class>org.jasig.cas.client.util.AssertionThreadLocalFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CAS Assertion Thread Local Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
request.getRemoteUser()为获取远程登录名
打开cas系统的配置文件cas-servlet.xml
<bean id="logoutAction" class="org.jasig.cas.web.flow.LogoutAction"
p:servicesManager-ref="servicesManager"
p:followServiceRedirects="${cas.logout.followServiceRedirects:true}"/>
//cas.logout.followServiceRedirects改为true 可以在退出后跳转到指定的页面
例如:<a href="http://localhost:9100/cas/logout?service=http://www.baidu.com">退出登录</a>
点击登陆之后 就会直接跳转到百度
设置CAS的用户名密码从数据库中获取
打开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/数据库名称?characterEncoding=utf8"
p:user="root"
p:password="123456" />
<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"/>
找到这个配置
<bean id="authenticationManager" class="org.jasig.cas.authentication.PolicyBasedAuthenticationManager">
<constructor-arg>
<map>
<entry key-ref="proxyAuthenticationHandler" value-ref="proxyPrincipalResolver" />
<entry key-ref="primaryAuthenticationHandler" value-ref="primaryPrincipalResolver" /> //改为dbAuthHandler,改为数据库查询的
</map>
</constructor-arg>
<property name="authenticationPolicy">
<bean class="org.jasig.cas.authentication.AnyAuthenticationPolicy" />
</property>
</bean>
修改CAS登陆页面为自己的登陆页面:
cas\WEB-INF\view\jsp\default\ui 找到casLoginView.jsp
将自己的登陆页面改为casLoginView.jsp 并在页面中添加指令
<%@ 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" %>
修改登陆页面的表单为
<form:form method="post" id="fm1" commandName="${commandName}" htmlEscape="true" class="sui-form"> //可以加上自己定义的样式
修改用户名框:
<form:input id="username" tabindex="1"
accesskey="${userNameAccessKey}" path="username" autocomplete="off" htmlEscape="true"
placeholder="邮箱/用户名/手机号" />
修改密码框:
<form:password id="password" tabindex="2" path="password"
accesskey="${passwordAccessKey}" htmlEscape="true" autocomplete="off"
placeholder="请输入密码" />
修改登陆按钮:
<input type="hidden" name="lt" value="${loginTicket}" />
<input type="hidden" name="execution" value="${flowExecutionKey}" />
<input type="hidden" name="_eventId" value="submit" />
<input accesskey="l" value="登陆" type="submit" />
在表单内加入错误提示:
<form:errors path="*" id="msg" cssClass="errors" element="div" htmlEscape="false" />
错误提示默认为英文,找到cas-servlet.xml
<bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver" p:defaultLocale="zh_CN" />
默认的为en zh_CN为中文(固定格式)
将下面两句话拷贝到messages_zh_CN.properties下 之后就会改为中文提示 用户名或密码错误
authenticationFailure.AccountNotFoundException=\u7528\u6237\u4E0D\u5B58\u5728.
authenticationFailure.FailedLoginException=\u5BC6\u7801\u9519\u8BEF.