• CAS5.3 单点登录/登出/springboot/springmvc


    环境:

    jdk:1.8

    cas server:5.3.14 + tomcat 8.5

    cas client:3.5.1

    客户端1:springmvc 传统web项目(使用web.xml)

    客户端2:springboot 

    参考博客:https://blog.csdn.net/anumbrella/category_7765386.html

    为了方便,没配置https.如果需要参考上面博客

    一.CAS 服务端搭建

    1.下载源码包:cas overlay github地址:https://github.com/apereo/cas-overlay-template/tree/5.3

    2.部署:

    在根目录下执行mvn clean package,下载依赖需要一段时间,如果有的包下载失败就要修改pom.xml比如xmlsectool的jar包要先从maven中央仓库手动下载,然后加进去,我的放到了图中的maven目录下

     以下是我修改的pom.xml,对xmlselectool依赖路径进行了更改,增加了json注册服务,jdbc验证等依赖包

      1 <?xml version="1.0" encoding="UTF-8"?>
      2 <project xmlns="http://maven.apache.org/POM/4.0.0"
      3          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      4          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd ">
      5 
      6 
      7     <modelVersion>4.0.0</modelVersion>
      8     <groupId>org.apereo.cas</groupId>
      9     <artifactId>cas-overlay</artifactId>
     10     <packaging>war</packaging>
     11     <version>1.0</version>
     12 
     13     <build>
     14         <plugins>
     15             <plugin>
     16                 <groupId>com.rimerosolutions.maven.plugins</groupId>
     17                 <artifactId>wrapper-maven-plugin</artifactId>
     18                 <version>0.0.5</version>
     19                 <configuration>
     20                     <verifyDownload>true</verifyDownload>
     21                     <checksumAlgorithm>MD5</checksumAlgorithm>
     22                 </configuration>
     23             </plugin>
     24             <plugin>
     25                 <groupId>org.springframework.boot</groupId>
     26                 <artifactId>spring-boot-maven-plugin</artifactId>
     27                 <version>${springboot.version}</version>
     28                 <configuration>
     29                     <mainClass>${mainClassName}</mainClass>
     30                     <addResources>true</addResources>
     31                     <executable>${isExecutable}</executable>
     32                     <layout>WAR</layout>
     33                 </configuration>
     34                 <executions>
     35                     <execution>
     36                         <goals>
     37                             <goal>repackage</goal>
     38                         </goals>
     39                     </execution>
     40                 </executions>
     41             </plugin>
     42             <plugin>
     43                 <groupId>org.apache.maven.plugins</groupId>
     44                 <artifactId>maven-war-plugin</artifactId>
     45                 <version>2.6</version>
     46                 <configuration>
     47                     <warName>cas</warName>
     48                     <failOnMissingWebXml>false</failOnMissingWebXml>
     49                     <recompressZippedFiles>false</recompressZippedFiles>
     50                     <archive>
     51                         <compress>false</compress>
     52                         <manifestFile>${manifestFileToUse}</manifestFile>
     53                     </archive>
     54                     <overlays>
     55                         <overlay>
     56                             <groupId>org.apereo.cas</groupId>
     57                             <artifactId>cas-server-webapp${app.server}</artifactId>
     58                         </overlay>
     59                     </overlays>
     60                 </configuration>
     61             </plugin>
     62             <plugin>
     63                 <groupId>org.apache.maven.plugins</groupId>
     64                 <artifactId>maven-compiler-plugin</artifactId>
     65                 <version>3.3</version>
     66             </plugin>
     67         </plugins>
     68         <finalName>cas</finalName>
     69     </build>
     70 
     71     <properties>
     72         <cas.version>5.3.14</cas.version>
     73         <springboot.version>1.5.18.RELEASE</springboot.version>
     74         <mybatis.spring.version>1.3.2</mybatis.spring.version>
     75         <mybatis.version>3.4.6</mybatis.version>
     76         <!-- app.server could be -jetty, -undertow, -tomcat, or blank if you plan to provide appserver -->
     77         <app.server>-tomcat</app.server>
     78 
     79         <mainClassName>org.springframework.boot.loader.WarLauncher</mainClassName>
     80         <isExecutable>false</isExecutable>
     81         <manifestFileToUse>${project.build.directory}/war/work/org.apereo.cas/cas-server-webapp${app.server}/META-INF/MANIFEST.MF</manifestFileToUse>
     82 
     83         <maven.compiler.source>1.8</maven.compiler.source>
     84         <maven.compiler.target>1.8</maven.compiler.target>
     85         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     86     </properties>
     87 
     88    <dependencies>
     89          <dependency>
     90             <groupId>net.shibboleth.tool</groupId>
     91             <artifactId>xmlsectool</artifactId>
     92             <version>2.0.0</version>
     93              <scope>system</scope>
     94             <systemPath>${pom.basedir}/maven/xmlsectool-2.0.0.jar</systemPath>
     95          </dependency>
     96        <!--新增支持jdbc验证-->
     97        <dependency>
     98            <groupId>org.apereo.cas</groupId>
     99            <artifactId>cas-server-support-jdbc</artifactId>
    100            <version>${cas.version}</version>
    101            <exclusions>
    102                <exclusion>
    103                    <artifactId>jul-to-slf4j</artifactId>
    104                    <groupId>org.slf4j</groupId>
    105                </exclusion>
    106            </exclusions>
    107        </dependency>
    108 
    109 
    110        <dependency>
    111            <groupId>org.apereo.cas</groupId>
    112            <artifactId>cas-server-core-cookie</artifactId>
    113            <version>${cas.version}</version>
    114        </dependency>
    115 
    116        <dependency>
    117            <groupId>org.apereo.cas</groupId>
    118            <artifactId>cas-server-support-jdbc-drivers</artifactId>
    119            <version>${cas.version}</version>
    120            <scope>runtime</scope>
    121        </dependency>
    122 
    123        <dependency>
    124            <groupId>org.apereo.cas</groupId>
    125            <artifactId>cas-server-core-configuration</artifactId>
    126            <version>${cas.version}</version>
    127        </dependency>
    128 
    129        <!-- Custom Authentication -->
    130        <dependency>
    131            <groupId>org.apereo.cas</groupId>
    132            <artifactId>cas-server-core-authentication-api</artifactId>
    133            <version>${cas.version}</version>
    134        </dependency>
    135 
    136        <!-- Custom Configuration -->
    137        <dependency>
    138            <groupId>org.apereo.cas</groupId>
    139            <artifactId>cas-server-core-configuration-api</artifactId>
    140            <version>${cas.version}</version>
    141        </dependency>
    142 
    143 
    144        <dependency>
    145            <groupId>org.apereo.cas</groupId>
    146            <artifactId>cas-server-support-json-service-registry</artifactId>
    147            <version>${cas.version}</version>
    148        </dependency>
    149 
    150        <!-- Authentication Attributes -->
    151        <dependency>
    152            <groupId>org.apereo.cas</groupId>
    153            <artifactId>cas-server-core-authentication-attributes</artifactId>
    154            <version>${cas.version}</version>
    155        </dependency>
    156 
    157        <dependency>
    158            <groupId>com.alibaba</groupId>
    159            <artifactId>fastjson</artifactId>
    160            <version>1.2.56</version>
    161        </dependency>
    162 
    163 
    164        <!-- lombok -->
    165        <dependency>
    166            <groupId>org.projectlombok</groupId>
    167            <artifactId>lombok</artifactId>
    168            <version>1.18.10</version>
    169            <scope>provided</scope>
    170        </dependency>
    171 
    172        <dependency>
    173            <groupId>org.apereo.cas</groupId>
    174            <artifactId>cas-server-core-webflow</artifactId>
    175            <version>${cas.version}</version>
    176        </dependency>
    177 
    178 
    179 
    180 
    181      </dependencies>
    182 
    183     <profiles>
    184         <profile>
    185             <activation>
    186                 <activeByDefault>true</activeByDefault>
    187             </activation>
    188             <id>default</id>
    189             <dependencies>
    190                 <dependency>
    191                     <groupId>org.apereo.cas</groupId>
    192                     <artifactId>cas-server-webapp${app.server}</artifactId>
    193                     <version>${cas.version}</version>
    194                     <type>war</type>
    195                     <scope>runtime</scope>
    196                 </dependency>
    197                 <!--
    198                 ...Additional dependencies may be placed here...
    199                 -->
    200             </dependencies>
    201         </profile>
    202 
    203         <profile>
    204             <activation>
    205                 <activeByDefault>false</activeByDefault>
    206             </activation>
    207             <id>exec</id>
    208             <properties>
    209                 <mainClassName>org.apereo.cas.web.CasWebApplication</mainClassName>
    210                 <isExecutable>true</isExecutable>
    211                 <manifestFileToUse></manifestFileToUse>
    212             </properties>
    213             <build>
    214                 <plugins>
    215                     <plugin>
    216                         <groupId>com.soebes.maven.plugins</groupId>
    217                         <artifactId>echo-maven-plugin</artifactId>
    218                         <version>0.3.0</version>
    219                         <executions>
    220                             <execution>
    221                                 <phase>prepare-package</phase>
    222                                 <goals>
    223                                     <goal>echo</goal>
    224                                 </goals>
    225                             </execution>
    226                         </executions>
    227                         <configuration>
    228                             <echos>
    229                                 <echo>Executable profile to make the generated CAS web application executable.</echo>
    230                             </echos>
    231                         </configuration>
    232                     </plugin>
    233                 </plugins>
    234             </build>
    235         </profile>
    236 
    237         <profile>
    238             <activation>
    239                 <activeByDefault>false</activeByDefault>
    240             </activation>
    241             <id>bootiful</id>
    242             <properties>
    243                 <app.server>-tomcat</app.server>
    244                 <isExecutable>false</isExecutable>
    245             </properties>
    246             <dependencies>
    247                 <dependency>
    248                     <groupId>org.apereo.cas</groupId>
    249                     <artifactId>cas-server-webapp${app.server}</artifactId>
    250                     <version>${cas.version}</version>
    251                     <type>war</type>
    252                     <scope>runtime</scope>
    253                 </dependency>
    254             </dependencies>
    255         </profile>
    256 
    257         <profile>
    258             <activation>
    259                 <activeByDefault>false</activeByDefault>
    260             </activation>
    261             <id>pgp</id>
    262             <build>
    263                 <plugins>
    264                     <plugin>
    265                         <groupId>com.github.s4u.plugins</groupId>
    266                         <artifactId>pgpverify-maven-plugin</artifactId>
    267                         <version>1.1.0</version>
    268                         <executions>
    269                             <execution>
    270                                 <goals>
    271                                     <goal>check</goal>
    272                                 </goals>
    273                             </execution>
    274                         </executions>
    275                         <configuration>
    276                             <pgpKeyServer>hkp://pool.sks-keyservers.net</pgpKeyServer>
    277                             <pgpKeysCachePath>${settings.localRepository}/pgpkeys-cache</pgpKeysCachePath>
    278                             <scope>test</scope>
    279                             <verifyPomFiles>true</verifyPomFiles>
    280                             <failNoSignature>false</failNoSignature>
    281                         </configuration>
    282                     </plugin>
    283                 </plugins>
    284             </build>
    285         </profile>
    286     </profiles>
    287 </project>
    View Code

    2.接下来我们要做一些定制化,如果想先看下效果参考https://blog.csdn.net/Anumbrella/article/details/81045885

    导入idea,导入的时候可以看到实际导入的是

    新建src/main/java和resources,鼠标放到项目上,然后F4,把java目录标记为sources,resources标记为resources

    从overlays目录下的WEB-INF拷贝services,META-INF文件夹已经application.properties到我们新建的resources目录下

    先说下services文件夹,该文件夹下的json文件定义了哪些应用要接入cas,命名格式为 app-id.json如

    重点讲下两个属性:1.serviceId定义哪些服务可以接入,可以写统配符,也可以用项目名2.attributeReleaseStrategy定义返回哪些属性,比如登录后返回的用户信息,其他的参考

    https://apereo.github.io/cas/5.3.x/installation/Service-Management.html,提醒下logouturl谨慎使用,一定概率造成无法单点退出

     

     application.properties,端口号,项目名,开启json服务识别

      1 ##
      2 # CAS Server Context Configuration
      3 #
      4 server.context-path=/cas
      5 #server.port=8443
      6 server.port=8090
      7 server.ssl.enabled=false
      8 #server.ssl.key-store=file:/etc/cas/thekeystore
      9 #server.ssl.key-store-password=changeit
     10 #server.ssl.key-password=changeit
     11         
     12 cas.tgc.secure=false
     13 
     14 spring.devtools.restart.enabled=true
     15 
     16 
     17 server.max-http-header-size=2097152
     18 server.use-forward-headers=true
     19 server.connection-timeout=20000
     20 server.error.include-stacktrace=ALWAYS
     21 
     22 server.compression.enabled=true
     23 server.compression.mime-types=application/javascript,application/json,application/xml,text/html,text/xml,text/plain
     24 
     25 server.tomcat.max-http-post-size=2097152
     26 server.tomcat.basedir=build/tomcat
     27 server.tomcat.accesslog.enabled=true
     28 server.tomcat.accesslog.pattern=%t %a "%r" %s (%D ms)
     29 server.tomcat.accesslog.suffix=.log
     30 server.tomcat.min-spare-threads=10
     31 server.tomcat.max-threads=200
     32 server.tomcat.port-header=X-Forwarded-Port
     33 server.tomcat.protocol-header=X-Forwarded-Proto
     34 server.tomcat.protocol-header-https-value=https
     35 server.tomcat.remote-ip-header=X-FORWARDED-FOR
     36 server.tomcat.uri-encoding=UTF-8
     37 
     38 spring.http.encoding.charset=UTF-8
     39 spring.http.encoding.enabled=true
     40 spring.http.encoding.force=true
     41 
     42 ##
     43 # CAS Cloud Bus Configuration
     44 #
     45 spring.cloud.bus.enabled=false
     46 
     47 # Indicates that systemPropertiesOverride can be used.
     48 # Set to false to prevent users from changing the default accidentally. Default true.
     49 spring.cloud.config.allow-override=true
     50 
     51 # External properties should override system properties.
     52 spring.cloud.config.override-system-properties=false
     53 
     54 # When allowOverride is true, external properties should take lowest priority, and not override any
     55 # existing property sources (including local config files).
     56 spring.cloud.config.override-none=false
     57 
     58 # spring.cloud.bus.refresh.enabled=true
     59 # spring.cloud.bus.env.enabled=true
     60 # spring.cloud.bus.destination=CasCloudBus
     61 # spring.cloud.bus.ack.enabled=true
     62 
     63 endpoints.enabled=false
     64 endpoints.sensitive=true
     65 
     66 endpoints.restart.enabled=false
     67 endpoints.shutdown.enabled=false
     68 
     69 # Control the security of the management/actuator endpoints
     70 # The 'enabled' flag below here controls the rendering of details for the health endpoint amongst other things.
     71 management.security.enabled=true
     72 management.security.roles=ACTUATOR,ADMIN
     73 management.security.sessions=if_required
     74 management.context-path=/status
     75 management.add-application-context-header=false
     76 
     77 # Define a CAS-specific "WARN" status code and its order
     78 management.health.status.order=WARN, DOWN, OUT_OF_SERVICE, UNKNOWN, UP
     79 
     80 # Control the security of the management/actuator endpoints
     81 # With basic authentication, assuming Spring Security and/or relevant modules are on the classpath.
     82 security.basic.authorize-mode=role
     83 security.basic.path=/cas/status/**
     84 security.basic.enabled=true
     85 security.user.name=casuser
     86 security.user.password=123
     87 
     88 ##
     89 # CAS Web Application Session Configuration
     90 #
     91 server.session.timeout=3000
     92 server.session.cookie.http-only=false
     93 server.session.tracking-modes=COOKIE
     94 
     95 ##
     96 # CAS Thymeleaf View Configuration
     97 #
     98 spring.thymeleaf.encoding=UTF-8
     99 spring.thymeleaf.cache=true
    100 spring.thymeleaf.mode=HTML
    101 spring.thymeleaf.template-resolver-order=100
    102 ##
    103 # CAS Log4j Configuration
    104 #
    105 # logging.config=file:/etc/cas/log4j2.xml
    106 server.context-parameters.isLog4jAutoInitializationDisabled=true
    107 
    108 ##
    109 # CAS AspectJ Configuration
    110 #
    111 spring.aop.auto=true
    112 spring.aop.proxy-target-class=true
    113 
    114 ##
    115 # CAS Authentication Credentials
    116 #
    117 #cas.authn.accept.users=wangyuancheng::Baizhu7958
    118 
    119 
    120 
    121 ##
    122 # Service Registry(服务注册)
    123 #
    124 # 开启识别Json文件,默认false
    125 cas.serviceRegistry.initFromJson=true
    126 
    127 #自动扫描服务配置,默认开启
    128 #cas.serviceRegistry.watcherEnabled=true
    129 
    130 #120秒扫描一遍
    131 cas.serviceRegistry.schedule.repeatInterval=120000
    132 
    133 #延迟15秒开启
    134 # cas.serviceRegistry.schedule.startDelay=15000
    135 
    136 ##
    137 # Json配置
    138 cas.serviceRegistry.json.location=classpath:/services
    139 
    140 
    141 cas.ticket.tgt.maxTimeToLiveInSeconds=28800
    142 cas.ticket.tgt.timeToKillInSeconds=7200
    143 cas.ticket.tgt.rememberMe.enabled=true
    144 # 使用次数
    145 cas.ticket.st.numberOfUses=1  
    146 # 过期时间100秒
    147 cas.ticket.st.timeToKillInSeconds=100 
    148 
    149 cas.httpClient.allowLocalLogoutUrls=true
    150 
    151 
    152 cas.slo.disabled=false
    153 cas.logout.followServiceRedirects=true
    154 cas.logout.removeDescendantTickets=true
    155 cas.slo.asynchronous=true

    默认情况下cas会提供一个jdbc的验证方式,把sql写在application.properties,但这种方式无法提供返回的用户信息,因此需要定义验证处理器及配置信息

     1 package cn.bz.bzsso.authentication;
     2 
     3 import cn.bz.bzsso.entity.User;
     4 import cn.bz.bzsso.handler.MyAuthenticationHandler;
     5 import cn.bz.bzsso.mapper.UserMapper;
     6 import org.apereo.cas.authentication.AuthenticationEventExecutionPlan;
     7 import org.apereo.cas.authentication.AuthenticationEventExecutionPlanConfigurer;
     8 import org.apereo.cas.authentication.AuthenticationHandler;
     9 import org.apereo.cas.authentication.principal.DefaultPrincipalFactory;
    10 import org.apereo.cas.configuration.CasConfigurationProperties;
    11 import org.apereo.cas.services.ServicesManager;
    12 import org.springframework.beans.factory.annotation.Autowired;
    13 import org.springframework.beans.factory.annotation.Qualifier;
    14 import org.springframework.boot.context.properties.EnableConfigurationProperties;
    15 import org.springframework.context.annotation.Bean;
    16 import org.springframework.context.annotation.Configuration;
    17 
    18 /**
    19  * @author tele
    20  * @Description
    21  * @create 2019-12-04
    22  */
    23 @Configuration("myAuthenticationConfiguration")
    24 @EnableConfigurationProperties(CasConfigurationProperties.class)
    25 public class MyAuthenticationConfiguration implements AuthenticationEventExecutionPlanConfigurer {
    26 
    27     @Autowired
    28     private CasConfigurationProperties casProperties;
    29 
    30     @Autowired
    31     @Qualifier("servicesManager")
    32     private ServicesManager servicesManager;
    33 
    34 
    35     /**
    36      * 将自定义验证器注册为Bean
    37      * @return
    38      */
    39     @Bean
    40     public AuthenticationHandler myAuthenticationHandler() {
    41         MyAuthenticationHandler handler = new MyAuthenticationHandler(MyAuthenticationHandler.class.getSimpleName(), servicesManager, new DefaultPrincipalFactory(), 1);
    42         return handler;
    43     }
    44 
    45     /**
    46      * 注册验证器
    47      * @param plan
    48      */
    49     @Override
    50     public void configureAuthenticationExecutionPlan(AuthenticationEventExecutionPlan plan) {
    51         plan.registerAuthenticationHandler(myAuthenticationHandler());
    52     }
    53 }
    View Code
     1 package cn.bz.bzsso.handler;
     2 
     3 import cn.bz.bzsso.entity.LoginCode;
     4 import cn.bz.bzsso.entity.LoginStatus;
     5 import cn.bz.bzsso.entity.User;
     6 import com.alibaba.fastjson.JSON;
     7 import com.alibaba.fastjson.serializer.SerializerFeature;
     8 import org.apereo.cas.authentication.AuthenticationHandlerExecutionResult;
     9 import org.apereo.cas.authentication.PreventedException;
    10 import org.apereo.cas.authentication.UsernamePasswordCredential;
    11 import org.apereo.cas.authentication.handler.support.AbstractUsernamePasswordAuthenticationHandler;
    12 import org.apereo.cas.authentication.principal.PrincipalFactory;
    13 import org.apereo.cas.services.ServicesManager;
    14 import org.springframework.jdbc.core.BeanPropertyRowMapper;
    15 import org.springframework.jdbc.core.JdbcTemplate;
    16 import org.springframework.jdbc.datasource.DriverManagerDataSource;
    17 import java.security.GeneralSecurityException;
    18 import java.util.ArrayList;
    19 import java.util.HashMap;
    20 import java.util.Map;
    21 
    22 /**
    23  * @author tele
    24  * @Description
    25  * @create 2019-12-04
    26  */
    27 public class MyAuthenticationHandler extends AbstractUsernamePasswordAuthenticationHandler {
    28 
    29 
    30     public MyAuthenticationHandler(String name, ServicesManager servicesManager, PrincipalFactory principalFactory, Integer order) {
    31         super(name, servicesManager, principalFactory, order);
    32     }
    33 
    34     @Override
    35     protected AuthenticationHandlerExecutionResult authenticateUsernamePasswordInternal(UsernamePasswordCredential credential, String originalPassword) throws GeneralSecurityException, PreventedException {
    36         String username = credential.getUsername();
    37         String password = credential.getPassword();
    38 
    39 
    40         DriverManagerDataSource dataSource = new DriverManagerDataSource();
    41         dataSource.setDriverClassName("com.mysql.jdbc.Driver");
    42         dataSource.setUrl("xx");
    43         dataSource.setUsername("xx");
    44         dataSource.setPassword("xx");
    45 
    46         // 创建JDBC模板
    47         JdbcTemplate jdbcTemplate = new JdbcTemplate();
    48         jdbcTemplate.setDataSource(dataSource);
    49 
    50         String sql = "select id,username,nickname,password from tb_user where username = ?";
    51 
    52         User user = (User) jdbcTemplate.queryForObject(sql, new Object[]{username}, new BeanPropertyRowMapper(User.class));
    53 
    54         LoginStatus loginStatus = new LoginStatus();
    55         loginStatus.setId(user.getId());
    56         loginStatus.setUsername(user.getUserName());
    57         loginStatus.setNickname(user.getNickName());
    58 
    59         if(user.getPassword().equals(password)) {
    60             loginStatus.setCode(LoginCode.LOGIN_SUCCESS);
    61             loginStatus.setMessage(LoginCode.MSG_LOGIN_SUCCESS);
    62         }else {
    63             loginStatus.setCode(LoginCode.ERROR_OF_USER_PWD);
    64             loginStatus.setMessage(LoginCode.MSG_ERROR_OF_USER_PWD);
    65         }
    66 
    67         Map<String,Object> resultMap = new HashMap<>(4);
    68 
    69         resultMap.put("loginStatus", JSON.toJSONString(loginStatus,SerializerFeature.WriteNullStringAsEmpty));
    70 
    71         return createHandlerResult(credential, this.principalFactory.createPrincipal(credential.getUsername(),resultMap), new ArrayList<>(0));
    72 
    73     }
    74 }
    View Code

    修改MATA-INF下的spring.factoriesorg.springframework.boot.autoconfigure.EnableAutoConfiguration=xx.MyAuthenticationConfiguration

    ok,服务端配置到此结束,你可以自定义返回的信息,状态码等

    二.客户端接入

    既然接入了cas,那么所有的客户端都应该关闭登录与退出接口,扒了下官网,看到一句话大概意思是cas不是一个session管理器,每个应用应当对自己的session负责,cas只会在退出时给接入的应用发通知,然后移除内部维护的tgt对象

    ,换句话说,每个应用内部应当调用session.invalidate()来销毁各自的session

    1.传统web项目接入.这种指的是带有web.xml的web

    加入cas-client 版本3.5.1依赖

     1 <!--CAS Client-->
     2 <dependency>
     3     <groupId>org.jasig.cas.client</groupId>
     4     <artifactId>cas-client-core</artifactId>
     5     <version>${cas-client.version}</version>
     6 </dependency>
     7 
     8 <dependency>
     9     <groupId>org.jasig.cas.client</groupId>
    10     <artifactId>cas-client-integration-tomcat-common</artifactId>
    11     <version>${cas-client.version}</version>
    12 </dependency>

    在web.xml中加入如下配置,本机环境不建议使用localhost,使用127.0.0.1(5.1版本使用localhost会有退出失效无法通信的问题,浏览器存储cookie时127.0.0.1和localhost是两个不同的文件夹)

    servername指的是客户端地址

     1 <listener>
     2         <listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
     3     </listener>
     4 
     5 
     6    <!-- 单点登出过滤器-->
     7     <filter>
     8         <filter-name>CAS Single Sign Out Filter</filter-name>
     9         <filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class>
    10         <init-param>
    11             <param-name>casServerUrlPrefix</param-name>
    12             <param-value>http://127.0.0.1:8090/cas/</param-value>
    13         </init-param>
    14     </filter>
    15     <filter-mapping>
    16         <filter-name>CAS Single Sign Out Filter</filter-name>
    17         <url-pattern>/*</url-pattern>
    18     </filter-mapping> 
    19     
    20    
    21 
    22     <!--用来跳转登录-->
    23     <filter>
    24         <filter-name>CAS Authentication Filter</filter-name>
    25         <filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
    26         <init-param>
    27             <param-name>casServerLoginUrl</param-name>
    28             <param-value>http://127.0.0.1:8090/cas/login</param-value>
    29         </init-param>
    30         <init-param>
    31             <param-name>serverName</param-name>
    32             <!--这是客户端的部署地址,认证时会带着这个地址,认证成功后会跳转到这个地址-->
    33             <param-value>http://127.0.0.1:8080</param-value>
    34         </init-param>
    35     </filter>
    36     <filter-mapping>
    37         <filter-name>CAS Authentication Filter</filter-name>
    38         <url-pattern>/*</url-pattern>
    39     </filter-mapping>
    40     
    41 
    42     <!--Ticket校验过滤器-->
    43     <filter>
    44         <filter-name>CAS Validation Filter</filter-name>
    45         <filter-class>org.jasig.cas.client.validation.Cas30ProxyReceivingTicketValidationFilter</filter-class>
    46         <init-param>
    47             <param-name>casServerUrlPrefix</param-name>
    48             <param-value>http://127.0.0.1:8090/cas/</param-value>
    49         </init-param>
    50         <init-param>
    51             <param-name>serverName</param-name>
    52            <param-value>http://127.0.0.1:8080</param-value>
    53         </init-param>
    54         <init-param>
    55             <param-name>redirectAfterValidation</param-name>
    56             <param-value>true</param-value>
    57         </init-param>
    58         <init-param>
    59             <param-name>useSession</param-name>
    60             <param-value>true</param-value>
    61         </init-param>
    62         <init-param>
    63             <param-name>authn_method</param-name>
    64             <param-value>mfa-duo</param-value>
    65         </init-param>
    66     </filter>
    67     <filter-mapping>
    68         <filter-name>CAS Validation Filter</filter-name>
    69         <url-pattern>/*</url-pattern>
    70     </filter-mapping>
    71     
    72      <!-- 该过滤器使得开发者可以通过org.jasig.cas.client.util.AssertionHolder来获取用户的登录名。-->
    73     <filter>
    74         <filter-name>CASAssertion Thread LocalFilter</filter-name>
    75         <filter-class>org.jasig.cas.client.util.AssertionThreadLocalFilter</filter-class>
    76     </filter>
    77     <filter-mapping>
    78         <filter-name>CASAssertion Thread LocalFilter</filter-name>
    79         <url-pattern>/*</url-pattern>
    80     </filter-mapping>
    81     
    82 
    83     <!-- 该过滤器负责实现HttpServletRequest请求包装-->
    84     <filter>
    85         <filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
    86         <filter-class>org.jasig.cas.client.util.HttpServletRequestWrapperFilter</filter-class>
    87     </filter>
    88     
    89      <filter-mapping>
    90         <filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
    91         <url-pattern>/*</url-pattern>
    92     </filter-mapping>

    客户端获得cas返回的登录信息的api,或者使用AssertionHolder.getAssertion().getPrincipal().getAttributes("xx");,严谨一点可以先判空,避免NPE

    1 @RequestMapping("/login")
    2 @ResponseBody
    3 public String login() {
    4     AttributePrincipal userPrincipal = (AttributePrincipal)request.getUserPrincipal();
    5     return userPrincipal.getAttributes().get("loginStatus").toString();
    6 }

    下面讲下退出

    @RequestMapping(value = "logout")
    public String logout(HttpSession session) throws InterruptedException {
    session.invalidate();
      return "redirect:" + CASConstant.LOGOUT_URL;
    }

    我在做的时候发现退出请求总是无法触发,后来发现是项目中有拦截器,于是加了一个excluedUrl,然后在对应的拦截器init的时候filterConfig.getInitParameter("excludedUrl");接下来dofilter时判断如果含有该路径重定向即可,但这样实际相当于重定向两次

     还有一个问题是上面redirect的地址如果需要spring静态注入,(当然写死可以),在applicationContext.xml中引入对应的url.properties,然后需要注入的常量类提供set方法即可,需要注意的是spring的注入是基于对象的.所以该set方法不能有static

    2.springboot 项目接入cas.springboot内置tomcat,不再需要加入tomcat

    pom.xml

     1 <properties>
     2         <java.version>1.8</java.version>
     3         <cas.client.version>3.5.1</cas.client.version>
     4 </properties>
     5 
     6 <dependencies>
     7 
     8 <!--cas的客户端 -->
     9 <dependency>
    10     <groupId>org.jasig.cas.client</groupId>
    11     <artifactId>cas-client-core</artifactId>
    12     <version>${cas.client.version}</version>
    13 </dependency>
    14 
    15 
    16 <dependency>
    17     <groupId>org.springframework.boot</groupId>
    18     <artifactId>spring-boot-devtools</artifactId>
    19     <optional>true</optional>
    20 </dependency>
    21 
    22 <dependency>
    23     <groupId>org.springframework.boot</groupId>
    24     <artifactId>spring-boot-configuration-processor</artifactId>
    25 </dependency>
    26 
    27 
    28 <dependency>
    29     <groupId>org.springframework.boot</groupId>
    30     <artifactId>spring-boot-starter-web</artifactId>
    31 </dependency>
    32 
    33 <dependency>
    34     <groupId>org.springframework.boot</groupId>
    35     <artifactId>spring-boot-autoconfigure</artifactId>
    36     <version>2.2.0.RELEASE</version>
    37 </dependency>
    38 
    39 <dependency>
    40     <groupId>org.mybatis.spring.boot</groupId>
    41     <artifactId>mybatis-spring-boot-starter</artifactId>
    42     <version>2.1.1</version>
    43 </dependency>
    44 
    45 <dependency>
    46     <groupId>mysql</groupId>
    47     <artifactId>mysql-connector-java</artifactId>
    48     <scope>runtime</scope>
    49 </dependency>
    50 
    51 <dependency>
    52     <groupId>com.alibaba</groupId>
    53     <artifactId>druid</artifactId>
    54     <version>1.1.10</version>
    55 </dependency>
    56 
    57 <dependency>
    58     <groupId>org.projectlombok</groupId>
    59     <artifactId>lombok</artifactId>
    60     <optional>true</optional>
    61 </dependency>
    62 <dependency>
    63     <groupId>org.springframework.boot</groupId>
    64     <artifactId>spring-boot-starter-test</artifactId>
    65     <scope>test</scope>
    66     <exclusions>
    67         <exclusion>
    68             <groupId>org.junit.vintage</groupId>
    69             <artifactId>junit-vintage-engine</artifactId>
    70         </exclusion>
    71     </exclusions>
    72 </dependency>
    73 </dependencies>    
    View Code

    在你的application.properties加入如下配置,依然建议使用127.0.0.1

     1 # 监听退出的接口,即所有接口都会进行监听
     2 spring.cas.sign-out-filters=/*
     3 # 需要拦截的认证的接口
     4 spring.cas.auth-filters=/*
     5 spring.cas.validate-filters=/*
     6 spring.cas.request-wrapper-filters=/*
     7 spring.cas.assertion-filters=/*
     8 # 表示忽略拦截的接口,也就是不用进行拦截
     9 spring.cas.ignore-filters=/test
    10 spring.cas.cas-server-login-url=http://127.0.0.1:8090/cas/login
    11 spring.cas.cas-server-url-prefix=http://127.0.0.1:8090/cas/
    12 spring.cas.redirect-after-validation=true
    13 spring.cas.use-session=true
    14 spring.cas.redirectAfterValidation=true
    15 # 客户端地址
    16 spring.cas.server-name=http://127.0.0.1:8081

    下面要注入之前在web.xml中配置的各种拦截器

    代码与参考的博客类似,做了些修改,@ConfigurationProperties依赖spring-boot-configuration-processor

      1 @Configuration
      2 public class CasCustomConfig {
      3     @Autowired
      4     SpringCasAutoconfig autoconfig;
      5 
      6     private static boolean casEnabled = true;
      7 
      8     public CasCustomConfig() {
      9     }
     10 
     11     @Bean
     12     public SpringCasAutoconfig getSpringCasAutoconfig() {
     13         return new SpringCasAutoconfig();
     14     }
     15 
     16     @Bean
     17     public ServletListenerRegistrationBean<SingleSignOutHttpSessionListener> singleSignOutHttpSessionListener() {
     18         ServletListenerRegistrationBean<SingleSignOutHttpSessionListener> listener = new ServletListenerRegistrationBean<SingleSignOutHttpSessionListener>();
     19         listener.setEnabled(casEnabled);
     20         listener.setListener(new SingleSignOutHttpSessionListener());
     21         listener.setOrder(1);
     22         return listener;
     23     }
     24 
     25 
     26 
     27     /**
     28      * 该过滤器用于实现单点登出功能,单点退出配置,一定要放在其他filter之前
     29      * @return
     30      */
     31     @Bean
     32     public FilterRegistrationBean singleSignOutFilter() {
     33         FilterRegistrationBean filterRegistration = new FilterRegistrationBean();
     34         filterRegistration.setFilter(new SingleSignOutFilter());
     35         filterRegistration.setEnabled(casEnabled);
     36         if (autoconfig.getSignOutFilters().size() > 0) {
     37             filterRegistration.setUrlPatterns(autoconfig.getSignOutFilters());
     38         } else {
     39             filterRegistration.addUrlPatterns("/*");
     40         }
     41         filterRegistration.addInitParameter("casServerUrlPrefix", autoconfig.getCasServerUrlPrefix());
     42         filterRegistration.addInitParameter("serverName",autoconfig.getServerName());
     43         filterRegistration.setOrder(1);
     44         return filterRegistration;
     45     }
     46 
     47 
     48     /**
     49      * 该过滤器负责用户的认证工作
     50      *
     51      * @return
     52      */
     53     @Bean
     54     public FilterRegistrationBean authenticationFilter() {
     55         FilterRegistrationBean filterRegistration = new FilterRegistrationBean();
     56         filterRegistration.setFilter(new AuthenticationFilter());
     57         filterRegistration.setEnabled(casEnabled);
     58         if (autoconfig.getAuthFilters().size() > 0) {
     59             filterRegistration.setUrlPatterns(autoconfig.getAuthFilters());
     60         } else {
     61             filterRegistration.addUrlPatterns("/*");
     62         }
     63         if (autoconfig.getIgnoreFilters() != null) {
     64             filterRegistration.addInitParameter("ignorePattern", autoconfig.getIgnoreFilters());
     65         }
     66         filterRegistration.addInitParameter("casServerLoginUrl", autoconfig.getCasServerLoginUrl());
     67         filterRegistration.addInitParameter("serverName", autoconfig.getServerName());
     68      //   filterRegistration.addInitParameter("useSession", autoconfig.isUseSession() ? "true" : "false");
     69      //   filterRegistration.addInitParameter("redirectAfterValidation", autoconfig.isRedirectAfterValidation() ? "true" : "false");
     70         filterRegistration.setOrder(2);
     71         return filterRegistration;
     72     }
     73 
     74     /**
     75      * 该过滤器负责对Ticket的校验工作,使用CAS 3.0协议
     76      *
     77      * @return
     78      */
     79     @Bean
     80     public FilterRegistrationBean cas30ProxyReceivingTicketValidationFilter() {
     81         FilterRegistrationBean filterRegistration = new FilterRegistrationBean();
     82         filterRegistration.setFilter(new Cas30ProxyReceivingTicketValidationFilter());
     83         filterRegistration.setEnabled(casEnabled);
     84         if (autoconfig.getValidateFilters().size() > 0) {
     85             filterRegistration.setUrlPatterns(autoconfig.getValidateFilters());
     86         } else {
     87             filterRegistration.addUrlPatterns("/*");
     88         }
     89         filterRegistration.addInitParameter("casServerUrlPrefix", autoconfig.getCasServerUrlPrefix());
     90         filterRegistration.addInitParameter("serverName", autoconfig.getServerName());
     91         filterRegistration.addInitParameter("useSession", autoconfig.isUseSession() ? "true" : "false");
     92         filterRegistration.addInitParameter("redirectAfterValidation", autoconfig.isRedirectAfterValidation() ? "true" : "false");
     93         filterRegistration.addInitParameter("authn_method", "mfa-duo");
     94         filterRegistration.setOrder(3);
     95         return filterRegistration;
     96     }
     97 
     98 
     99     /**
    100      * 该过滤器使得可以通过org.jasig.cas.client.util.AssertionHolder来获取用户的登录名。
    101      * 比如AssertionHolder.getAssertion().getPrincipal().getName()。
    102      * 这个类把Assertion信息放在ThreadLocal变量中,这样应用程序不在web层也能够获取到当前登录信息
    103      *
    104      * @return
    105      */
    106     @Bean
    107     public FilterRegistrationBean assertionThreadLocalFilter() {
    108         FilterRegistrationBean filterRegistration = new FilterRegistrationBean();
    109         filterRegistration.setFilter(new AssertionThreadLocalFilter());
    110         filterRegistration.setEnabled(true);
    111         if (autoconfig.getAssertionFilters().size() > 0) {
    112             filterRegistration.setUrlPatterns(autoconfig.getAssertionFilters());
    113         } else {
    114             filterRegistration.addUrlPatterns("/*");
    115         }
    116         filterRegistration.setOrder(4);
    117         return filterRegistration;
    118     }
    119 
    120 
    121     @Bean
    122     public FilterRegistrationBean httpServletRequestWrapperFilter() {
    123         FilterRegistrationBean filterRegistration = new FilterRegistrationBean();
    124         filterRegistration.setFilter(new HttpServletRequestWrapperFilter());
    125         filterRegistration.setEnabled(true);
    126         if (autoconfig.getRequestWrapperFilters().size() > 0) {
    127             filterRegistration.setUrlPatterns(autoconfig.getRequestWrapperFilters());
    128         } else {
    129             filterRegistration.addUrlPatterns("/*");
    130         }
    131         filterRegistration.setOrder(5);
    132         return filterRegistration;
    133     }
    134 }
    View Code
      1 @ConfigurationProperties(prefix = "spring.cas")
      2 public class SpringCasAutoconfig {
      3 
      4     static final String separator = ",";
      5 
      6     private String validateFilters;
      7     private String signOutFilters;
      8     private String authFilters;
      9     private String assertionFilters;
     10     private String requestWrapperFilters;
     11     private String ignoreFilters; //需要放行的url,多个可以使用|分隔,遵循正则
     12 
     13     private String casServerUrlPrefix;
     14     private String casServerLoginUrl;
     15     private String serverName;
     16     private boolean useSession = true;
     17     private boolean redirectAfterValidation = true;
     18 
     19     public String getIgnoreFilters() {
     20         return ignoreFilters;
     21     }
     22 
     23     public void setIgnoreFilters(String ignoreFilters) {
     24         this.ignoreFilters = ignoreFilters;
     25     }
     26 
     27     public List<String> getValidateFilters() {
     28         return Arrays.asList(validateFilters.split(separator));
     29     }
     30 
     31     public void setValidateFilters(String validateFilters) {
     32         this.validateFilters = validateFilters;
     33     }
     34 
     35     public List<String> getSignOutFilters() {
     36         return Arrays.asList(signOutFilters.split(separator));
     37     }
     38 
     39     public void setSignOutFilters(String signOutFilters) {
     40         this.signOutFilters = signOutFilters;
     41     }
     42 
     43     public List<String> getAuthFilters() {
     44         return Arrays.asList(authFilters.split(separator));
     45     }
     46 
     47     public void setAuthFilters(String authFilters) {
     48         this.authFilters = authFilters;
     49     }
     50 
     51     public List<String> getAssertionFilters() {
     52         return Arrays.asList(assertionFilters.split(separator));
     53     }
     54 
     55     public void setAssertionFilters(String assertionFilters) {
     56         this.assertionFilters = assertionFilters;
     57     }
     58 
     59     public List<String> getRequestWrapperFilters() {
     60         return Arrays.asList(requestWrapperFilters.split(separator));
     61     }
     62 
     63     public void setRequestWrapperFilters(String requestWrapperFilters) {
     64         this.requestWrapperFilters = requestWrapperFilters;
     65     }
     66 
     67     public String getCasServerUrlPrefix() {
     68         return casServerUrlPrefix;
     69     }
     70 
     71     public void setCasServerUrlPrefix(String casServerUrlPrefix) {
     72         this.casServerUrlPrefix = casServerUrlPrefix;
     73     }
     74 
     75     public String getCasServerLoginUrl() {
     76         return casServerLoginUrl;
     77     }
     78 
     79     public void setCasServerLoginUrl(String casServerLoginUrl) {
     80         this.casServerLoginUrl = casServerLoginUrl;
     81     }
     82 
     83     public String getServerName() {
     84         return serverName;
     85     }
     86 
     87     public void setServerName(String serverName) {
     88         this.serverName = serverName;
     89     }
     90 
     91     public boolean isRedirectAfterValidation() {
     92         return redirectAfterValidation;
     93     }
     94 
     95     public void setRedirectAfterValidation(boolean redirectAfterValidation) {
     96         this.redirectAfterValidation = redirectAfterValidation;
     97     }
     98 
     99     public boolean isUseSession() {
    100         return useSession;
    101     }
    102 
    103     public void setUseSession(boolean useSession) {
    104         this.useSession = useSession;
    105     }
    106 }
    View Code

    接下来时登录和登出,不要直接丢个@RestController就完事了,这个主解会让redirect失效,当成字符串转成json返回了,最好的方式是使用@Controller,需要转json的加上@ResponseBody

     1 @Controller
     2 public class LoginController {
     3 
     4     @Autowired
     5     private UserMapper userMapper;
     6 
     7     @Autowired
     8     private HttpServletRequest request;
     9 
    10     @RequestMapping("/login")
    11     @ResponseBody
    12     public String login() {
    13         AttributePrincipal userPrincipal = (AttributePrincipal)request.getUserPrincipal();
    14         return userPrincipal.getAttributes().get("loginStatus").toString();
    15     }
    16 
    17     @RequestMapping("/logout")
    18     public String logout(HttpSession session) {
    19         session.removeAttribute(AbstractCasFilter.CONST_CAS_ASSERTION);
    20         session.invalidate();
    21         return "redirect:http://127.0.0.1:8090/cas/logout?service=http://127.0.0.1:8081/spring_boot/login/";
    22     }
    23 
    24     private void println(Object object) {
    25         System.out.println(object);
    26     }
    27 }

    三.验证

     

     

     三.关于源码

    源码看了下客户端的拦截器与处理器,大概流程如下,在浏览器输入http://127.0.0.1:8081/spring_boot/login/会被重定向到http://127.0.0.1:8090/cas/login?service=http://127.0.0.1:8081/spring_boot/login/,也就是cas的登录页,点击登录之后,cas server进行验证,之后会进入客户端的拦截器SingleSignOutFilter,拦截器判断请求类型,如果是tokenrequest(带token的请求),保存session和st,如果是登出请求,将st,session从map中移除,在destroySession中session.invalidate(),但是其他接入的客户端并没有销毁session,退出时,cas只会给接入的客户端发通知,当然从哪个客户端发起的退出该客户端的session会被destroy,但其他客户端要在登出接口中session.invalidate(),

    
    
  • 相关阅读:
    爬虫那些事儿---爬虫选择策略
    爬虫那些事儿--Http返回码
    【珍藏】linux 同步IO: sync、fsync与fdatasync
    perf学习-linux自带性能分析工具
    进程调度原理
    phpmyadmin 免登陆
    请为main函数提供返回值
    悬挂else引发的问题
    PhpMyAdmin导入数据库大小限制?
    linux内核Makefile整体分析
  • 原文地址:https://www.cnblogs.com/tele-share/p/12024043.html
Copyright © 2020-2023  润新知