单点登录解决方案 CAS

一、CAS快速入门

1.1CAS服务端部署

(1). 将cas-overlay-template-5-3.zip解压
(2). 修改pom.xml,在<!--...Additional dependencies may be placed here...-->注释下添加依赖

 <!--数据库相关 start-->
                <dependency>
                    <groupId>org.apereo.cas</groupId>
                    <artifactId>cas-server-support-jdbc</artifactId>
                    <version>${cas.version}</version>
                </dependency>
                <dependency>
                    <groupId>org.apereo.cas</groupId>
                    <artifactId>cas-server-support-jdbc-drivers</artifactId>
                    <version>${cas.version}</version>
                </dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.32</version>
</dependency>
                <!--数据库相关 end-->

(3). 进入cas-overlay-template-5.3目录,执行命令

mvn package

(4). 把target下生成的war包重命名为cas.war放到tomcat 启动tomcat后自动解压war 包

(5). 打开浏览器输入 http://localhost:8080/cas ,系统有内置的用户名和密码分别是 casuser 和Mellon,输入后登录验证成功.

(6).由于使用的静态密码为casuser::Mellon不好记忆, 修改密码---  到apache-tomcat8.5.33webappscasWEB-INFclasses目录的application.properties的最后面修改密码 为如下

cas.authn.accept.users=admin::admin

2.1 配置兼容http协议
(1)由于CAS默认使用的是基于https协议,需要改为兼容使用http协议 到apachetomcat-8.5.33webappscasWEB-INFclasses目录的application.properties添加如下 的内容

#允许http
cas.tgc.secure=false
cas.serviceRegistry.initFromJson=true

**TGC(cas.tgc.secure):Ticket Granted Cookie  (客户端用户持有,传送到服务器,用于验证)
    存放用户身份认证凭证的cookie,在浏览器和CAS Server间通讯时使用,并且只能基 于安全通道传输(Https),是CAS Server用来明确用户身份的凭证。**

(2)到apache-tomcat-8.5.33webappscasWEB-INFclassesservices目录下的 HTTPSandIMAPS-10000001.json 修改内容如下

"serviceId" : "^(https|imaps)://.*" 
改为==>
"serviceId" : "^(https|http|imaps)://.*",

修改以上配置后,启动cas服务端进行测试。

2.1.1CAS客户端开发-原生方式

(1)新建demo工程,pom.xml 添加配置

<packaging>war</packaging>

    <dependencies>
        <dependency>
            <groupId>org.jasig.cas.client</groupId>
            <artifactId>cas-client-core</artifactId>
            <version>3.3.3</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.4</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <configuration>
                    <port>9001</port>
                    <path>/</path>
                </configuration>
            </plugin>
        </plugins>
    </build>

(2)新建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:8080/cas/login</param-value>
            <!--这里的server是服务端的IP -->  
        </init-param>  
        <init-param>  
            <param-name>serverName</param-name>  
            <param-value>http://localhost:9001</param-value>
        </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:8080/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>
    <!-- ======================== 单点登录结束 ======================== -->  

</web-app>

(3)新增index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>秒杀</title>
</head>
<body>
<%=request.getRemoteUser()%> , 欢迎来到秒杀~


</body>
</html>

(4)测试: 启动cas服务端和客户端,浏览器输入http://localhost:9001 ,系统自动跳 转到服务端的登录页面,输入正确的用户名和密码后,跳转回客户端工程。

(5)再创建一个一样的cas客户端程序(秒杀2),端口为9002,测试两个系统单点 登录的效果。即登录其中一个系统,另外一个系统则不用登录。

2.2.2 CAS客户端开发-Spring Security整合

(1)创建 demo工程,pom.xml引入依赖

<packaging>war</packaging>

    <properties>
        <spring.version>5.0.5.RELEASE</spring.version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-config</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-cas</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.jasig.cas.client</groupId>
            <artifactId>cas-client-core</artifactId>
            <version>3.3.3</version>
            <exclusions>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>log4j-over-slf4j</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
            <scope>provided</scope>
        </dependency>

    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <configuration>
                    <!-- 指定端口 -->
                    <port>9003</port>
                    <!-- 请求路径 -->
                    <path>/</path>
                </configuration>
            </plugin>
        </plugins>
    </build>

(2)添加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">    

       <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath: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>
    
</web-app>

(3)添加spring-security.xml

 <?xml version="1.0" encoding="UTF-8"?>
<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">
    
    <!--   entry-point-ref  入口点引用 -->
    <http use-expressions="false" entry-point-ref="casProcessingFilterEntryPoint">  
        <intercept-url pattern="/**" access="ROLE_USER"/>   
        <csrf disabled="true"/>  
        <!-- custom-filter为过滤器(替换spring Security过滤器), 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>
    <!--1.use-expressions:  是否启动SPEL表达式 默认是true。不启用例子:access="ROLE_USER",启用例子:access="hasRole('ROLE_USER')"
        2.entry-point-ref:security框架接入第三方服务所需要配置(切入点)。

 -->
    
      <!-- CAS入口点 开始  主要作用:配置CAS服务端地址-->
    <beans:bean id="casProcessingFilterEntryPoint" class="org.springframework.security.cas.web.CasAuthenticationEntryPoint">  
        <!-- 单点登录服务器登录URL -->  
        <beans:property name="loginUrl" value="http://localhost:8080/cas/login"/>
        <beans:property name="serviceProperties" ref="serviceProperties"/>  
    </beans:bean>
    <!--serviceProperties中value的配置是web服务器的主机+/login/cas,该URL是service的 值,会依据该值在CAS Server上生成ticket, 然后用来到WEB服务器上验证ticket。
     概括的说:主要是生成票据ticket
    -->
    <beans:bean id="serviceProperties" class="org.springframework.security.cas.ServiceProperties">  
        <!--service 配置自身工程的根地址+/login/cas(/login/cas为固定写法,必须的)   -->
        <beans:property name="service" value="http://localhost:9003/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="userDetailsService" />  
            </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://localhost:8080/cas"/>
            </beans:bean>  
        </beans:property>  
        <beans:property name="key" value="an_id_for_this_auth_provider_only"/> 
    </beans:bean>        
            <!-- 认证类 -->
    <beans:bean id="userDetailsService" class="cn.itcast.demo.service.UserDetailServiceImpl"/>
    
    <!-- 认证过滤器 结束 -->

    <!-- 单点登出  开始  -->     
    <beans:bean id="singleLogoutFilter" class="org.jasig.cas.client.session.SingleSignOutFilter"/>  <!-- CAS原生的单点退出-->
    <beans:bean id="requestSingleLogoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter">  <!--主要作用: value="/logout/cas"映射到CAS单点退出地址-->
        <beans:constructor-arg value="http://localhost:8080/cas/logout"/>
        <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)添加UserDetailServiceImpl

package cn.itcast.demo.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;

public class UserDetailServiceImpl implements UserDetailsService {

    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        List<GrantedAuthority> authorityList=new ArrayList<GrantedAuthority>();
        authorityList.add(new SimpleGrantedAuthority("ROLE_USER"));
        return new User(username,"",authorityList);
    }
}

(5)添加index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="org.springframework.security.core.context.SecurityContextHolder" %>
<html>
<head>
    <title>用户中心</title>
</head>
<body>
<%= SecurityContextHolder.getContext().getAuthentication().getName()%> , 欢迎来到用户中心~
<a href="/logout/cas">退出</a>


</body>
</html>

二、项目整合

  • 修改apache-tomcat8.5.33/webapps/cas/WEB-INF/classes目录的application.properties:
#用户登陆
cas.authn.jdbc.query[0].url=jdbc:mysql://localhost:3306/qingcheng_user?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false
cas.authn.jdbc.query[0].user=root
cas.authn.jdbc.query[0].password=root
cas.authn.jdbc.query[0].sql=select password from tb_user where username=?
cas.authn.jdbc.query[0].fieldPassword=password
cas.authn.jdbc.query[0].driverClass=com.mysql.jdbc.Driver

#密码加密类型
cas.authn.jdbc.query[0].passwordEncoder.type=BCRYPT
cas.authn.jdbc.query[0].passwordEncoder.characterEncoding=UTF-8


#允许http
cas.tgc.secure=false
cas.serviceRegistry.initFromJson=true
  • 自定义登陆界面替换CAS登陆界面
    规范:     
  • 静态资源(js,css)存放目录为WEB-INFclassesstatic
  • html资源(thymeleaf模板)存放目录为WEB-INFclassestemplates
      
  • 主题配置文件存放在WEB-INFclasses,并且命名为[theme_name].properties
    (1)在apache-tomcat-8.5.37\webapps\cas\WEB-INF\classes\static\themes目录下创 建qingcheng文件夹,将静态原型中的img和css等文件夹拷入此文件夹;
    (2)在apache-tomcat-8.5.37\webappscas\WEB-INF\classes\templates目录下创建 qingcheng文件夹,将静态原型中的login.html拷贝至此文件夹,并改名为 casLoginView.html, 修改casLoginView.html内容:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">

样式图片等资源路径,改成绝对目录

 <link rel="stylesheet" type="text/css" href="/cas/themes/qingcheng/css/all.css" />
 <link rel="stylesheet" type="text/css" href="/cas/themes/qingcheng/css/pages-login.css" />

表单部分:

 <form class="sui-form" method="post" th:object="${credential}" >
                                <div class="input-prepend"><span class="add-on loginname"></span>
                                    <input id="inputName" type="text" placeholder="邮箱/用户名/手机号" class="span2 input-xfat"  th:field="*{username}">
                                </div>
                                <div class="input-prepend"><span class="add-on loginpwd"></span>
                                    <input id="inputPassword" type="password" placeholder="请输入密码" class="span2 input-xfat"  th:field="*{password}">
                                </div>
                                <div class="setting">
                                    <label class="checkbox inline">
                                        <input name="m1" type="checkbox" value="2" checked="">
                                        自动登录
                                    </label>
                                    <span class="forget">忘记密码?</span>
                                </div>
                                <div class="logined">
                                <!--从cas原登陆页面拷贝start-->
                                    <input type="hidden" name="execution" th:value="${flowExecutionKey}"/>
                                    <input type="hidden" name="_eventId" value="submit"/>
                                    <input type="hidden" name="geolocation"/>
                                    <!--从cas原登陆页面拷贝start-->
                                    <button class="sui-btn btn-block btn-xlarge btn-danger"  target="_blank">登&nbsp;&nbsp;录</button>
                                </div>
                                <div class="alert alert-danger" <!--cas原登陆页面错误弹窗--> th:if="${#fields.hasErrors('*')}">
                                   <span th:each="err : ${#fields.errors('*')}" th:utext="${err}"></span>
                                </div>
                            </form>

th:object,用法:th:object="${brand}",(用来接受后台传过来的对象)
th:field,用法:th:field="*{name}",(用来绑定后台对象和表单数据)
*{} 选择表达式(星号表达式)选择表达式与变量表达式有一个重要的区别:选择表达 式计算的是选定的对象,而不是整个环境变量映射。也就是:只要是没有选择的对象, 选择表达式与变量表达式的语法是完全一样的。那什么是选择的对象呢?是一个: th:object对象属性绑定的对象

(3)在apache-tomcat-8.5.37\webapps\cas\WEB-INF\classes下创建 qingcheng.properties

  cas.standard.css.file=/css/cas.css

(4)修改apache-tomcat-8.5.37\webapps\cas\WEBINF\classes\application.properties

 cas.theme.defaultThemeName=qingcheng

其他页面也类似操作

1.创建CAS公共模块

(1)创建qingcheng_common_cas工程( cas公共模块),pom.xml引入依赖:

<dependencies>
        <dependency>
            <groupId>com.qingcheng</groupId>
            <artifactId>qingcheng_common_web</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-cas</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.9.4</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.4</version>
        </dependency>
    </dependencies>

(2)qingcheng_common_cas工程添加配置文件spring-security.xml

  配置文件中已经配置login/username.do可匿名访问

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
             xmlns:beans="http://www.springframework.org/schema/beans"
             xmlns:context="http://www.springframework.org/schema/context" 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/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" />

    <http pattern="/css/**" security="none"></http>
    <http pattern="/js/**" security="none"></http>
    <http pattern="/img/**" security="none"></http>


    <!--   entry-point-ref  入口点引用 -->
    <http use-expressions="false" entry-point-ref="casProcessingFilterEntryPoint">
        <!--IS_AUTHENTICATED_ANONYMOUSLY 代表可以匿名访问-->
        <intercept-url pattern="/login/username.do" access="IS_AUTHENTICATED_ANONYMOUSLY"></intercept-url>
        <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="${cas_url}/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="${service_url}/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="userDetailsService" />
            </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="${cas_url}"/>
            </beans:bean>
        </beans:property>
        <beans:property name="key" value="an_id_for_this_auth_provider_only"/>
    </beans:bean>
    <!-- 认证类 -->
    <beans:bean id="userDetailsService" class="com.qingcheng.service.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="${cas_url}/logout"/>
        <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>

(3)qingcheng_common_cas工程创建UserDetailServiceImpl

 public class UserDetailServiceImpl implements UserDetailsService {
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        System.out.printf("...经过UserDetailServiceImpl");
        //这个类没有校验用户密码的功能  ,给当前用户赋予权限(角色)
        List<GrantedAuthority> grantedAuthorityList=new ArrayList<GrantedAuthority>();
        grantedAuthorityList.add(new SimpleGrantedAuthority("ROLE_USER"));
        return new User(username,"",grantedAuthorityList);
    }
}

(4).qingcheng_common_cas工程创建LoginController(公共模块获取登录名)

@RestController
@RequestMapping("/login")
public class LoginController {
    /**
     * 获取用户名
     * @return
     */
    @GetMapping("/username")
    public Map username(){
        String name = SecurityContextHolder.getContext().getAuthentication().getName();//得到登录账户名
        //没登录则name=anonymousUser,spring-security.xml配置匿名访问设置
        System.out.printf("++++++++++++++++++++++登录用户名:"+name);
        if("anonymousUser".equals(name)){
           name="";
        }
        Map map=new HashMap();
        map.put("username",name);
        return map;
    }
}

2.portal工程集成单点登录

(1)qingcheng_portal的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">
  <!-- 解决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>
    <init-param>
      <param-name>forceEncoding</param-name>
      <param-value>true</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>CharacterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>



  <!--spring Security配置 , 必须加在springMVC前面-->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath*: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>



  <servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!-- 指定加载的配置文件 ,通过参数contextConfigLocation加载-->
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath*:applicationContext*.xml</param-value>
    </init-param>
  </servlet>

  <servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <url-pattern>*.do</url-pattern>
  </servlet-mapping>

  <welcome-file-list>
    <welcome-file>/index.do</welcome-file>
  </welcome-file-list>
  
</web-app>

(2)引入CAS公共模块依赖

 <dependencies>
    <dependency>
        <groupId>com.qingcheng</groupId>
        <artifactId>qingcheng_interface</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
    <dependency>
        <groupId>com.qingcheng</groupId>
        <artifactId>qingcheng_common_cas</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
    <dependency>
        <groupId>org.thymeleaf</groupId>
        <artifactId>thymeleaf-spring5</artifactId>
        <version>3.0.11.RELEASE</version>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.tomcat.maven</groupId>
            <artifactId>tomcat7-maven-plugin</artifactId>
            <configuration>
                <!-- 指定端口 -->
                <port>9102</port>
                <!-- 请求路径 -->
                <path>/</path>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <source>8</source>
                <target>8</target>
            </configuration>
        </plugin>
    </plugins>
</build>

(3)添加配置文件cas.properties

 cas_url=http://localhost:8080/cas
 service_url=http://localhost:9102

(4)添加配置文件spring-security-portal.xml

  <?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
             xmlns:beans="http://www.springframework.org/schema/beans"
             xmlns:context="http://www.springframework.org/schema/context" 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/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">


    <http pattern="/index.do" security="none"></http>
    <http pattern="/search.do" security="none"></http>


</beans:beans>

(5).前端页面显示登录名
<script src="./js/vue.js"></script>

<script src="./js/axios.js"></script>
<script>
    new Vue({
        el:'#app',
        data(){
            return{
                username:''
            }
        },
        created(){
            axios.get(`/login/username.do`).then(response =>{
                this.username=response.data.username;
            })
        }
    })
            </script>

判断是否为空显示用户名或登录
<span v-if="username==''">

                        <li class="f-item">请
                        <a href="login.html" target="_blank">登录</a>
                        <span>
                            <a href="register.html" target="_blank">免费注册</a>
                        </span>
                    </li>
                    </span>
                    <span v-if="username!=''">
                        {{username}}<a href="/logout/cas">退出登录</a>
                    </span>

4.退出登录后返回首页

修改cas服务端的配置文件 application.properties(最终修改后)

#用户登陆
cas.authn.jdbc.query[0].url=jdbc:mysql://localhost:3306/qingcheng_user?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false
cas.authn.jdbc.query[0].user=root
cas.authn.jdbc.query[0].password=root
cas.authn.jdbc.query[0].sql=select password from tb_user where username=?
cas.authn.jdbc.query[0].fieldPassword=password
cas.authn.jdbc.query[0].driverClass=com.mysql.jdbc.Driver

#密码加密类型
cas.authn.jdbc.query[0].passwordEncoder.type=BCRYPT
cas.authn.jdbc.query[0].passwordEncoder.characterEncoding=UTF-8


#允许http
cas.tgc.secure=false
cas.serviceRegistry.initFromJson=true


cas.theme.defaultThemeName=qingcheng

#退出登录返回首页
cas.logout.redirectUrl=http://localhost:9102/index.do

备注:可以创建login.html文件做跳板(登录后返回首页)

 <a href="login.html">登录</a><!--index.html登录按钮  -->

     <script>
       location.href="index.do"
   </script>
Last modification:January 22nd, 2020 at 12:31 am

Leave a Comment