分布式系统存在诸多子系统,而这些子系统是分别部署在不同的服务器中,那么使用传统方式的session是无法解决的,我们需要使用相关的单点登录技术来解决
单点登录(Single Sign On),简称为 SSO,是目前比较流行的企业业务整合的解决方案之一。SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统
CAS 是 Yale 大学发起的一个开源项目,旨在为 Web 应用系统提供一种可靠的单点登录方法,CAS 在 2004 年 12 月正式成为 JA-SIG 的一个项目
CAS 具有以下特点:
从结构上看,CAS 包含两个部分: CAS Server
和 CAS Client
,CAS Server 需要独立部署
,主要负责对用户的认证工作;CAS Client 负责处理对客户端受保护资源的访问请求,需要登录时,重定向到 CAS Server
,下图是 CAS 最基本的协议过程
SSO单点登录访问流程主要有以下步骤:
首先Maven项目 cas_demo1客户端系统
在cas_demo1 pom文件中添加依赖,并将此项目打包方式改成war包
<packaging>warpackaging>
<dependencies>
<dependency>
<groupId>org.jasig.cas.clientgroupId>
<artifactId>cas-client-coreartifactId>
<version>3.3.3version>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>servlet-apiartifactId>
<version>2.5version>
<scope>providedscope>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.mavengroupId>
<artifactId>tomcat7-maven-pluginartifactId>
<version>2.2version>
<configuration>
<port>9001port>
<path>/path>
configuration>
plugin>
plugins>
build>
<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.SingleSignOutHttpSessionListenerlistener-class>
listener>
<filter>
<filter-name>CAS Single Sign Out Filterfilter-name>
<filter-class>org.jasig.cas.client.session.SingleSignOutFilterfilter-class>
filter>
<filter-mapping>
<filter-name>CAS Single Sign Out Filterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
<filter>
<filter-name>CASFilterfilter-name> <filter-class>org.jasig.cas.client.authentication.AuthenticationFilterfilter-class>
<init-param>
<param-name>casServerLoginUrlparam-name>
<param-value>http://192.168.25.120:9000/cas/loginparam-value>
init-param>
<init-param>
<param-name>serverNameparam-name>
<param-value>http://localhost:9001param-value>
init-param>
filter>
<filter-mapping>
<filter-name>CASFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
<filter>
<filter-name>CAS Validation Filterfilter-name>
<filter-class> org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilterfilter-class>
<init-param>
<param-name>casServerUrlPrefixparam-name>
<param-value>http://192.168.25.120:9000/casparam-value>
init-param>
<init-param>
<param-name>serverNameparam-name>
<param-value>http://localhost:9001param-value>
init-param>
filter>
<filter-mapping>
<filter-name>CAS Validation Filterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
<filter>
<filter-name>CAS HttpServletRequest Wrapper Filterfilter-name>
<filter-class>
org.jasig.cas.client.util.HttpServletRequestWrapperFilterfilter-class>
filter>
<filter-mapping>
<filter-name>CAS HttpServletRequest Wrapper Filterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
<filter>
<filter-name>CAS Assertion Thread Local Filterfilter-name> <filter-class>org.jasig.cas.client.util.AssertionThreadLocalFilterfilter-class>
filter>
<filter-mapping>
<filter-name>CAS Assertion Thread Local Filterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
web-app>
<%--
Created by IntelliJ IDEA.
User: jinsa
Date: 2020/2/7
Time: 13:58
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>欢迎使用单点登陆CAS--ONEtitle>
head>
<body>
<h1>欢迎 : <%=request.getRemoteUser()%> 访问单点登陆系统--ONE ONEh1>
body>
html>
<%--
Created by IntelliJ IDEA.
User: jinsa
Date: 2020/2/7
Time: 13:58
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>欢迎使用单点登陆CAS--TWOtitle>
head>
<body>
<h1>欢迎 : <%=request.getRemoteUser()%> 访问单点登陆系统--TWO TWOh1>
body>
html>
http://192.168.25.120:9000/cas/logout
<a href="http://192.168.25.120:9000/cas/logout?service=http://www.baidu.com">单点退出</a>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
p:driverClass="com.mysql.jdbc.Driver"
p:jdbcUrl="jdbc:mysql://localhost:3306/你的数据库名称?characterEncoding=utf8"
p:user="root"
p:password="root" />
<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"/>
/home/pyg/passport-cas/tomcat-cas/webapps/cas/WEB-INF/view/jsp/default/ui/
目录下casLoginView.jsp
更换成你自己的html页面,注意名字要一样,可以把之前的备份<%@ 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" %>
# 默认标签 添加你自己的class就行
<form:form method="post" id="fm1" commandName="${commandName}" htmlEscape="true">
<form:errors path="*" id="msg" cssClass="errors" element="div" htmlEscape="false" />
# 结束标签 </form:form>
# 这是CAS默认的 添加你自己的class
<form:input cssClass="required" cssErrorClass="error" id="username" size="25" tabindex="1" accesskey="${userNameAccessKey}" path="username" autocomplete="off" htmlEscape="true" />
# 同上
<form:password cssClass="required" cssErrorClass="error" id="password" size="25" tabindex="2" path="password" accesskey="${passwordAccessKey}" htmlEscape="true" autocomplete="off" />
# 这里的变量是默认的 更改你自己的内容 class
<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" />
<dependency>
<groupId>org.springframework.securitygroupId>
<artifactId>spring-security-casartifactId>
<version>4.1.0.RELEASEversion>
dependency>
<dependency>
<groupId>org.jasig.cas.clientgroupId>
<artifactId>cas-client-coreartifactId>
<version>3.3.3version>
<exclusions>
<exclusion>
<groupId>org.slf4jgroupId>
<artifactId>log4j-over-slf4jartifactId>
exclusion>
exclusions>
dependency>
<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.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd">
<http pattern="/register.html" 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>
<http pattern="/data/**" security="none">http>
<http pattern="/user/register/**" security="none">http>
<http pattern="/user/sendSms/**" security="none">http>
<http use-expressions="false" entry-point-ref="casProcessingFilterEntryPoint">
<intercept-url pattern="/**" access="ROLE_USER"/>
<csrf disabled="true"/>
<custom-filter ref="casAuthenticationFilter" position="CAS_FILTER" />
<custom-filter ref="requestSingleLogoutFilter" before="LOGOUT_FILTER"/>
<custom-filter ref="singleLogoutFilter" before="CAS_FILTER"/>
http>
<beans:bean id="casProcessingFilterEntryPoint" class="org.springframework.security.cas.web.CasAuthenticationEntryPoint">
<beans:property name="loginUrl" value="http://192.168.25.120:9000/cas/login"/>
<beans:property name="serviceProperties" ref="serviceProperties"/>
beans:bean>
<beans:bean id="serviceProperties" class="org.springframework.security.cas.ServiceProperties">
<beans:property name="service" value="http://localhost:8086/login/cas"/>
beans:bean>
<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="userDetailsService" />
beans:bean>
beans:property>
<beans:property name="serviceProperties" ref="serviceProperties"/>
<beans:property name="ticketValidator">
<beans:bean class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator">
<beans:constructor-arg index="0" value="http://192.168.25.120:9000/cas"/>
beans:bean>
beans:property>
<beans:property name="key" value="an_id_for_this_auth_provider_only"/>
beans:bean>
<beans:bean id="userDetailsService" class="自己定义"/>
<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://192.168.25.120:9000/cas/logout?service=http://192.168.25.120:9000/cas/login"/>
<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>
package com.pyg.user.service;
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;
import java.util.ArrayList;
import java.util.List;
/**
* @ Description
* @ auther 宁宁小可爱
* @ create 2020-02-07 16:20
*/
public class UserDetailServiceImpl implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// 创建集合 封装角色权限 查询数据库工作已经交给CAS完成了
List<GrantedAuthority> list = new ArrayList<>();
list.add(new SimpleGrantedAuthority("ROLE_USER"));
return new User(username,"",list);
}
}