cas单点登录-动态添加services(十三)

安全框架 同时被 2 个专栏收录
64 篇文章 0 订阅
23 篇文章 4 订阅

前面我们整合客户端的时候,需要在cas服务端注册,使用的是json文件的方式,更简单的一点,直接配置为只要是http或者https的请求,都表示注册,那也就没有本篇的动态添加services了,哈哈 不过,这也是一个不错的方法。
假如,我们以域名配置的,比如:http://app1.cas.com 注册,那么又有新的模块为 http://app2.cas.com 我们总不能每次修改配置,重启cas服务吧。这很不现实,官网给出了如下的解决方式,将数据库来存储这些数据。

具体参考官网

https://apereo.github.io/cas/5.3.x/installation/Configuration-Properties.html#database-service-registry
https://apereo.github.io/cas/5.3.x/installation/JPA-Service-Management.html
https://apereo.github.io/cas/5.3.x/installation/Configuration-Properties-Common.html#database-settings

配置过程 

pom添加依赖

<dependency>
    <groupId>org.apereo.cas</groupId>
    <artifactId>cas-server-support-jpa-service-registry</artifactId>
    <version>${cas.version}</version>
</dependency>
<dependency>
    <groupId>org.apereo.cas</groupId>
    <artifactId>cas-server-core-services-api</artifactId>
    <version>${cas.version}</version>
</dependency>
<dependency>
    <groupId>org.apereo.cas</groupId>
    <artifactId>cas-server-core-authentication-attributes</artifactId>
    <version>${cas.version}</version>
</dependency>

application.properties添加以下属性 

#数据库用户名
cas.serviceRegistry.jpa.user=root
#数据库密码
cas.serviceRegistry.jpa.password=123456
#mysql驱动
cas.serviceRegistry.jpa.driverClass=com.mysql.jdbc.Driver
#数据库连接
cas.serviceRegistry.jpa.url=jdbc:mysql://127.0.0.1:3306/testshiro?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false
cas.serviceRegistry.dialect=org.hibernate.dialect.MySQLDialect
#连接池配置
cas.serviceRegistry.jpa.pool.suspension=false
cas.serviceRegistry.jpa.pool.minSize=6
cas.serviceRegistry.jpa.pool.maxSize=18
cas.serviceRegistry.jpa.pool.maxWait=2000
cas.serviceRegistry.jpa.pool.timeoutMillis=1000
#默认为create-drop,表示每次启动服务都会清除你之前注册的cas服务
cas.serviceRegistry.jpa.ddlAuto=create-drop

修改service/HTTPSandIMAPS-10000001.json

为了方便测试,将服务注册只允许app1.cas.com

package com.wangsaichao.cas.controller;

import org.apereo.cas.services.*;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.net.URL;


/**
 * @author: wangsaichao
 * @date: 2018/8/10
 * @description:
 */
@RestController
public class ServiceController {

    private Logger logger = LoggerFactory.getLogger(ServiceController.class);

    @Autowired
    @Qualifier("servicesManager")
    private ServicesManager servicesManager;

    /**
     * 注册service
     * @param serviceId 域名
     * @param id 顺序
     * @return
     */
    @RequestMapping(value = "/addClient/{serviceId}/{id}",method = RequestMethod.GET)
    public Object addClient(@PathVariable("serviceId") String serviceId, @PathVariable("id") int id) {
        try {
            String a="^(https|imaps|http)://"+serviceId+".*";
            RegexRegisteredService service = new RegexRegisteredService();
            ReturnAllAttributeReleasePolicy re = new ReturnAllAttributeReleasePolicy();
            service.setServiceId(a);
            service.setId(id);
            service.setAttributeReleasePolicy(re);
            service.setName("login");
            //这个是为了单点登出而作用的
            service.setLogoutUrl(new URL("http://"+serviceId));
            servicesManager.save(service);
            //执行load让他生效
            servicesManager.load();
            ReturnMessage returnMessage = new ReturnMessage();
            returnMessage.setCode(200);
            returnMessage.setMessage("添加成功");
            return returnMessage;
        } catch (Exception e) {
            logger.error("注册service异常",e);
            ReturnMessage returnMessage = new ReturnMessage();
            returnMessage.setCode(500);
            returnMessage.setMessage("添加失败");
            return returnMessage;
        }
    }

    /**
     * 删除service异常
     * @param serviceId
     * @return
     */
    @RequestMapping(value = "/deleteClient/{serviceId}/{id}",method = RequestMethod.GET)
    public Object deleteClient(@PathVariable("serviceId") String serviceId,@PathVariable("id") int id) {
        try {

//            String a="^(https|imaps|http)://"+serviceId+".*";
//            String a="^(https|imaps|http)://"+serviceId+".*";
//            RegexRegisteredService service = new RegexRegisteredService();
//            ReturnAllAttributeReleasePolicy re = new ReturnAllAttributeReleasePolicy();
//            service.setServiceId(a);
//            service.setId(id);
//            service.setAttributeReleasePolicy(re);
//            service.setName("login");
//            //这个是为了单点登出而作用的
//            service.setLogoutUrl(new URL("http://"+serviceId));
            String aa = "http://app2.cas.com:8082";
            RegisteredService service = servicesManager.findServiceBy(aa);
            servicesManager.delete(service);
            //执行load生效
            servicesManager.load();

            ReturnMessage returnMessage = new ReturnMessage();
            returnMessage.setCode(200);
            returnMessage.setMessage("删除成功");
            return returnMessage;
        } catch (Exception e) {
            logger.error("删除service异常",e);
            ReturnMessage returnMessage = new ReturnMessage();
            returnMessage.setCode(500);
            returnMessage.setMessage("删除失败");
            return returnMessage;
        }
    }

    public class ReturnMessage{

        private Integer code;

        private String message;

        public Integer getCode() {
            return code;
        }

        public void setCode(Integer code) {
            this.code = code;
        }

        public String getMessage() {
            return message;
        }

        public void setMessage(String message) {
            this.message = message;
        }
    }





}

增加http接口,操作数据库添加或删除service

这里为了方便直接在地址栏操作增加或删除。代码如下:

package com.wangsaichao.cas.controller;

import org.apereo.cas.services.*;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.net.URL;


/**
 * @author: wangsaichao
 * @date: 2018/8/10
 * @description:
 */
@RestController
public class ServiceController {

    private Logger logger = LoggerFactory.getLogger(ServiceController.class);

    @Autowired
    @Qualifier("servicesManager")
    private ServicesManager servicesManager;

    /**
     * 注册service
     * @param serviceId 域名
     * @param id 顺序
     * @return
     */
    @RequestMapping(value = "/addClient/{serviceId}/{id}",method = RequestMethod.GET)
    public Object addClient(@PathVariable("serviceId") String serviceId, @PathVariable("id") int id) {
        try {
            String a="^(https|imaps|http)://"+serviceId+".*";
            RegexRegisteredService service = new RegexRegisteredService();
            ReturnAllAttributeReleasePolicy re = new ReturnAllAttributeReleasePolicy();
            service.setServiceId(a);
            service.setId(id);
            service.setAttributeReleasePolicy(re);
            service.setName("login");
            //这个是为了单点登出而作用的
            service.setLogoutUrl(new URL("http://"+serviceId));
            servicesManager.save(service);
            //执行load让他生效
            servicesManager.load();
            ReturnMessage returnMessage = new ReturnMessage();
            returnMessage.setCode(200);
            returnMessage.setMessage("添加成功");
            return returnMessage;
        } catch (Exception e) {
            logger.error("注册service异常",e);
            ReturnMessage returnMessage = new ReturnMessage();
            returnMessage.setCode(500);
            returnMessage.setMessage("添加失败");
            return returnMessage;
        }
    }

    /**
     * 删除service异常
     * @param serviceId
     * @return
     */
    @RequestMapping(value = "/deleteClient/{serviceId}/{id}",method = RequestMethod.GET)
    public Object deleteClient(@PathVariable("serviceId") String serviceId,@PathVariable("id") int id) {
        try {

//            String a="^(https|imaps|http)://"+serviceId+".*";
//            String a="^(https|imaps|http)://"+serviceId+".*";
//            RegexRegisteredService service = new RegexRegisteredService();
//            ReturnAllAttributeReleasePolicy re = new ReturnAllAttributeReleasePolicy();
//            service.setServiceId(a);
//            service.setId(id);
//            service.setAttributeReleasePolicy(re);
//            service.setName("login");
//            //这个是为了单点登出而作用的
//            service.setLogoutUrl(new URL("http://"+serviceId));
            String aa = "http://app2.cas.com:8082";
            RegisteredService service = servicesManager.findServiceBy(aa);
            servicesManager.delete(service);
            //执行load生效
            servicesManager.load();

            ReturnMessage returnMessage = new ReturnMessage();
            returnMessage.setCode(200);
            returnMessage.setMessage("删除成功");
            return returnMessage;
        } catch (Exception e) {
            logger.error("删除service异常",e);
            ReturnMessage returnMessage = new ReturnMessage();
            returnMessage.setCode(500);
            returnMessage.setMessage("删除失败");
            return returnMessage;
        }
    }

    public class ReturnMessage{

        private Integer code;

        private String message;

        public Integer getCode() {
            return code;
        }

        public void setCode(Integer code) {
            this.code = code;
        }

        public String getMessage() {
            return message;
        }

        public void setMessage(String message) {
            this.message = message;
        }
    }

启动服务

1.启动服务报错

Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘type=MyISAM’ at line 5
这里写图片描述
原因是上面的配置:cas.serviceRegistry.dialect=org.hibernate.dialect.MySQLDialect 应该改为:
cas.serviceRegistry.dialect=org.hibernate.dialect.MySQL5Dialect

2.停止服务,将会删除之前创建的service

为了避免重启服务,导致之前的services丢失,需要将
cas.serviceRegistry.jpa.ddlAuto=update
每次启动之后,会在mysql中自动生成以下表格

这里写图片描述

测试过程中的问题

在添加service的时候没问题,但是在删除service的时候报以下异常:
java.lang.IllegalArgumentException: ‘actionPerformed’ cannot be null.
Check the correctness of @Audit annotation at the following audit point: execution(public synchronized org.apereo.cas.services.RegisteredService
经过debug发现,代码其实是没问题的,可以正常删除,但是在执行AuditTrailManagementAspect类中下面这段代码的时候报异常:
这里写图片描述
我们发现auditActionResolver和auditResourceResolver是null,经过搜索,找到了下面这篇文章,在此感谢作者,博客地址:
https://www.qyh.me/space/java/article/cas-sso-different-application

原文如下:

搜了一下Audit这玩意叫什么审计日志,google了半天也没看到源码(github上面有个,但cas的应该是在此基础上修改过的),无奈之下看了 WEB-INF/spring-configuration/auditTrailContext.xml 这个文件,这才发现,里面根本就没有 DELETE_SERVICE_ACTION_RESOLVER和DELETE_SERVICE_RESOURCE_RESOLVER这两个值对应的Resolver。。。 这可能跟cas的版本或者编译情况有关,真是不明白为什么save方法有但是delete方法就没有了,在这上面卡了好久。

解决办法:

因为我用的是cas5.3.2是springboot版本的,已经没有文中所说的那个文件了,通过查看源码,打算使用以下方式解决。
自定义starter,跟之前自定义cas-client-starter一样。中间整合的过程,出现很多错误,没有一步一步,记录,到时候请看源码。只是依赖了原始audit的api包,至于下面的CasCoreAuditConfiguration类是从原始cas-server-core-audit包中拷贝出来的,然后需要自定义一个cas-server-core-audit的starter包来覆盖原来的包,这个包必须也叫cas-server-core-audit因为在cas-server-webapp${app.server}中依赖了这个包,并且scope是runtime类型的,没办法,只能写一个一模一样的包了。

自定义cas-server-core-audit包

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>org.apereo.cas</groupId>
    <artifactId>cas-server-core-audit</artifactId>
    <version>5.3.2</version>
    <packaging>jar</packaging>
    <name>cas-server-core-audit</name>
    <description>cas-server-core-audit</description>

    <!-- 引用依赖的父包 -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.0.RELEASE</version>
    </parent>

    <properties>
        <cas.version>5.3.2</cas.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apereo.cas</groupId>
            <artifactId>cas-server-core-api-configuration-model</artifactId>
            <version>${cas.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apereo.cas</groupId>
            <artifactId>cas-server-core-util-api</artifactId>
            <version>${cas.version}</version>
        </dependency><dependency>
            <groupId>org.apereo.cas</groupId>
            <artifactId>cas-server-core-audit-api</artifactId>
            <version>${cas.version}</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.9.1</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.5.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
            <!-- 配置该插件将源码放入仓库 -->
            <plugin>
                <artifactId>maven-source-plugin</artifactId>
                <version>2.1</version>
                <configuration>
                    <attach>true</attach>
                </configuration>
                <executions>
                    <execution>
                        <phase>compile</phase>
                        <goals>
                            <goal>jar</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

CasCoreAuditConfiguration.java 

package org.apereo.cas.audit.spi.config;

import org.apache.commons.lang3.StringUtils;
import org.apereo.cas.audit.*;
import org.apereo.cas.audit.spi.*;
import org.apereo.cas.configuration.CasConfigurationProperties;
import org.apereo.cas.configuration.model.core.audit.AuditProperties;
import org.apereo.cas.configuration.model.core.audit.AuditSlf4jLogProperties;
import org.apereo.cas.util.CollectionUtils;
import org.apereo.inspektr.audit.AuditTrailManagementAspect;
import org.apereo.inspektr.audit.spi.AuditActionResolver;
import org.apereo.inspektr.audit.spi.AuditResourceResolver;
import org.apereo.inspektr.audit.spi.support.DefaultAuditActionResolver;
import org.apereo.inspektr.audit.support.Slf4jLoggingAuditTrailManager;
import org.apereo.inspektr.common.spi.PrincipalResolver;
import org.apereo.inspektr.common.web.ClientInfoThreadLocalFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * This is {@link CasCoreAuditConfiguration}.
 *
 * @author Misagh Moayyed
 * @since 5.0.0
 */
@Configuration("casCoreAuditConfiguration")
@EnableAspectJAutoProxy
@EnableConfigurationProperties(CasConfigurationProperties.class)
public class CasCoreAuditConfiguration implements AuditTrailExecutionPlanConfigurer, AuditTrailRecordResolutionPlanConfigurer {

    private static final Logger LOGGER = LoggerFactory.getLogger(CasCoreAuditConfiguration.class);

    private static final String AUDIT_ACTION_SUFFIX_FAILED = "_FAILED";

    @Autowired
    private CasConfigurationProperties casProperties;

    @Autowired
    private ApplicationContext applicationContext;

    @Bean
    public AuditTrailManagementAspect auditTrailManagementAspect(@Qualifier("auditTrailExecutionPlan") final AuditTrailExecutionPlan auditTrailExecutionPlan,
                                                                 @Qualifier("auditTrailRecordResolutionPlan") final AuditTrailRecordResolutionPlan auditTrailRecordResolutionPlan) {
        final AuditTrailManagementAspect aspect = new AuditTrailManagementAspect(
                casProperties.getAudit().getAppCode(),
                auditablePrincipalResolver(auditPrincipalIdProvider()),
                auditTrailExecutionPlan.getAuditTrailManagers(), auditTrailRecordResolutionPlan.getAuditActionResolvers(),
                auditTrailRecordResolutionPlan.getAuditResourceResolvers());
        aspect.setFailOnAuditFailures(!casProperties.getAudit().isIgnoreAuditFailures());
        return aspect;
    }

    @Autowired
    @ConditionalOnMissingBean(name = "auditTrailRecordResolutionPlan")
    @Bean
    public AuditTrailRecordResolutionPlan auditTrailRecordResolutionPlan(final List<AuditTrailRecordResolutionPlanConfigurer> configurers) {
        final DefaultAuditTrailRecordResolutionPlan plan = new DefaultAuditTrailRecordResolutionPlan();
        configurers.forEach(c -> {
            final String name = StringUtils.removePattern(c.getClass().getSimpleName(), "\\$.+");
            LOGGER.debug("Registering audit trail manager [{}]", name);
            c.configureAuditTrailRecordResolutionPlan(plan);
        });
        return plan;
    }

    @Autowired
    @ConditionalOnMissingBean(name = "auditTrailExecutionPlan")
    @Bean
    public AuditTrailExecutionPlan auditTrailExecutionPlan(final List<AuditTrailExecutionPlanConfigurer> configurers) {
        final DefaultAuditTrailExecutionPlan plan = new DefaultAuditTrailExecutionPlan();
        configurers.forEach(c -> {
            final String name = StringUtils.removePattern(c.getClass().getSimpleName(), "\\$.+");
            LOGGER.debug("Registering audit trail manager [{}]", name);
            c.configureAuditTrailExecutionPlan(plan);
        });
        return plan;
    }

    @Bean
    public FilterRegistrationBean casClientInfoLoggingFilter() {
        final AuditProperties audit = casProperties.getAudit();

        final FilterRegistrationBean bean = new FilterRegistrationBean();
        bean.setFilter(new ClientInfoThreadLocalFilter());
        bean.setUrlPatterns(CollectionUtils.wrap("/*"));
        bean.setName("CAS Client Info Logging Filter");
        bean.setAsyncSupported(true);
        bean.setOrder(Ordered.HIGHEST_PRECEDENCE);

        final Map<String, String> initParams = new HashMap<>();
        if (StringUtils.isNotBlank(audit.getAlternateClientAddrHeaderName())) {
            initParams.put(ClientInfoThreadLocalFilter.CONST_IP_ADDRESS_HEADER, audit.getAlternateClientAddrHeaderName());
        }

        if (StringUtils.isNotBlank(audit.getAlternateServerAddrHeaderName())) {
            initParams.put(ClientInfoThreadLocalFilter.CONST_SERVER_IP_ADDRESS_HEADER, audit.getAlternateServerAddrHeaderName());
        }

        initParams.put(ClientInfoThreadLocalFilter.CONST_USE_SERVER_HOST_ADDRESS, String.valueOf(audit.isUseServerHostAddress()));
        bean.setInitParameters(initParams);
        return bean;
    }

    @ConditionalOnMissingBean(name = "deleteServiceActionResolver")
    @Bean
    public AuditActionResolver deleteServiceActionResolver() {
        return new DeleteServiceActionResolver();
    }

    @ConditionalOnMissingBean(name = "deleteServiceResourceResolver")
    @Bean
    public AuditResourceResolver deleteServiceResourceResolver() {
        return new DeleteServiceResourceResolver();
    }


    @ConditionalOnMissingBean(name = "authenticationActionResolver")
    @Bean
    public AuditActionResolver authenticationActionResolver() {
        return new DefaultAuditActionResolver("_SUCCESS", AUDIT_ACTION_SUFFIX_FAILED);
    }

    @ConditionalOnMissingBean(name = "ticketCreationActionResolver")
    @Bean
    public AuditActionResolver ticketCreationActionResolver() {
        return new DefaultAuditActionResolver("_CREATED", "_NOT_CREATED");
    }

    @ConditionalOnMissingBean(name = "ticketValidationActionResolver")
    @Bean
    public AuditActionResolver ticketValidationActionResolver() {
        return new DefaultAuditActionResolver("D", AUDIT_ACTION_SUFFIX_FAILED);
    }

    @ConditionalOnMissingBean(name = "returnValueResourceResolver")
    @Bean
    public AuditResourceResolver returnValueResourceResolver() {
        return new ShortenedReturnValueAsStringResourceResolver();
    }

    @ConditionalOnMissingBean(name = "nullableReturnValueResourceResolver")
    @Bean
    public AuditResourceResolver nullableReturnValueResourceResolver() {
        return new NullableReturnValueAuditResourceResolver(returnValueResourceResolver());
    }

    @ConditionalOnMissingBean(name = "serviceAccessEnforcementAuditResourceResolver")
    @Bean
    public ServiceAccessEnforcementAuditResourceResolver serviceAccessEnforcementAuditResourceResolver() {
        return new ServiceAccessEnforcementAuditResourceResolver();
    }

    /**
     * Extension point for deployers to define custom AuditActionResolvers to extend the stock resolvers.
     *
     * @return the map
     */
    @ConditionalOnMissingBean(name = "customAuditActionResolverMap")
    @Bean
    public Map<String, AuditActionResolver> customAuditActionResolverMap() {
        return new HashMap<>(0);
    }

    /**
     * Extension point for deployers to define custom AuditResourceResolvers to extend the stock resolvers.
     *
     * @return the map
     */
    @ConditionalOnMissingBean(name = "customAuditResourceResolverMap")
    @Bean
    public Map<String, AuditResourceResolver> customAuditResourceResolverMap() {
        return new HashMap<>(0);
    }

    @ConditionalOnMissingBean(name = "auditablePrincipalResolver")
    @Bean
    public PrincipalResolver auditablePrincipalResolver(@Qualifier("auditPrincipalIdProvider") final AuditPrincipalIdProvider auditPrincipalIdProvider) {
        return new ThreadLocalPrincipalResolver(auditPrincipalIdProvider);
    }

    @ConditionalOnMissingBean(name = "ticketResourceResolver")
    @Bean
    public AuditResourceResolver ticketResourceResolver() {
        return new TicketAsFirstParameterResourceResolver();
    }

    @ConditionalOnMissingBean(name = "ticketValidationResourceResolver")
    @Bean
    public AuditResourceResolver ticketValidationResourceResolver() {
        final AuditProperties audit = casProperties.getAudit();
        if (audit.isIncludeValidationAssertion()) {
            return new TicketValidationResourceResolver();
        }
        return ticketResourceResolver();
    }

    @ConditionalOnMissingBean(name = "messageBundleAwareResourceResolver")
    @Bean
    public AuditResourceResolver messageBundleAwareResourceResolver() {
        return new MessageBundleAwareResourceResolver(applicationContext);
    }

    @ConditionalOnMissingBean(name = "auditPrincipalIdProvider")
    @Bean
    public AuditPrincipalIdProvider auditPrincipalIdProvider() {
        final Map<String, AuditPrincipalIdProvider> resolvers = applicationContext.getBeansOfType(AuditPrincipalIdProvider.class, false, true);
        final List<AuditPrincipalIdProvider> providers = new ArrayList<>(resolvers.values());
        AnnotationAwareOrderComparator.sort(providers);
        return new ChainingAuditPrincipalIdProvider(providers);
    }

    @Override
    public void configureAuditTrailExecutionPlan(final AuditTrailExecutionPlan plan) {
        final AuditSlf4jLogProperties audit = casProperties.getAudit().getSlf4j();
        final Slf4jLoggingAuditTrailManager slf4j = new Slf4jLoggingAuditTrailManager();
        slf4j.setUseSingleLine(audit.isUseSingleLine());
        slf4j.setEntrySeparator(audit.getSinglelineSeparator());
        slf4j.setAuditFormat(audit.getAuditFormat());
        plan.registerAuditTrailManager(slf4j);
    }

    @Override
    public void configureAuditTrailRecordResolutionPlan(final AuditTrailRecordResolutionPlan plan) {


        final AuditActionResolver deleteServiceActionResolver = deleteServiceActionResolver();
        plan.registerAuditActionResolver("DELETE_SERVICE_ACTION_RESOLVER",deleteServiceActionResolver);

        final AuditResourceResolver deleteServiceResourceResolver = deleteServiceResourceResolver();
        plan.registerAuditResourceResolver("DELETE_SERVICE_RESOURCE_RESOLVER",deleteServiceResourceResolver);

        /*
            Add audit action resolvers here.
         */
        final AuditActionResolver resolver = authenticationActionResolver();
        plan.registerAuditActionResolver("AUTHENTICATION_RESOLVER", resolver);
        plan.registerAuditActionResolver("SAVE_SERVICE_ACTION_RESOLVER", resolver);

        final AuditActionResolver defResolver = new DefaultAuditActionResolver();
        plan.registerAuditActionResolver("DESTROY_TICKET_GRANTING_TICKET_RESOLVER", defResolver);
        plan.registerAuditActionResolver("DESTROY_PROXY_GRANTING_TICKET_RESOLVER", defResolver);

        final AuditActionResolver cResolver = ticketCreationActionResolver();
        plan.registerAuditActionResolver("CREATE_PROXY_GRANTING_TICKET_RESOLVER", cResolver);
        plan.registerAuditActionResolver("GRANT_SERVICE_TICKET_RESOLVER", cResolver);
        plan.registerAuditActionResolver("GRANT_PROXY_TICKET_RESOLVER", cResolver);
        plan.registerAuditActionResolver("CREATE_TICKET_GRANTING_TICKET_RESOLVER", cResolver);

        final AuditActionResolver authResolver = new DefaultAuditActionResolver("_TRIGGERED", StringUtils.EMPTY);
        plan.registerAuditActionResolver("AUTHENTICATION_EVENT_ACTION_RESOLVER", authResolver);
        plan.registerAuditActionResolver("VALIDATE_SERVICE_TICKET_RESOLVER", ticketValidationActionResolver());

        final AuditActionResolver serviceAccessResolver = new DefaultAuditActionResolver("_TRIGGERED", StringUtils.EMPTY);
        plan.registerAuditActionResolver("SERVICE_ACCESS_ENFORCEMENT_ACTION_RESOLVER", serviceAccessResolver);

        /*
            Add audit resource resolvers here.
         */
        plan.registerAuditResourceResolver("AUTHENTICATION_RESOURCE_RESOLVER", new CredentialsAsFirstParameterResourceResolver());

        final AuditResourceResolver messageBundleAwareResourceResolver = messageBundleAwareResourceResolver();
        plan.registerAuditResourceResolver("CREATE_TICKET_GRANTING_TICKET_RESOURCE_RESOLVER", messageBundleAwareResourceResolver);
        plan.registerAuditResourceResolver("CREATE_PROXY_GRANTING_TICKET_RESOURCE_RESOLVER", messageBundleAwareResourceResolver);

        final AuditResourceResolver ticketResourceResolver = ticketResourceResolver();
        plan.registerAuditResourceResolver("DESTROY_TICKET_GRANTING_TICKET_RESOURCE_RESOLVER", ticketResourceResolver);
        plan.registerAuditResourceResolver("DESTROY_PROXY_GRANTING_TICKET_RESOURCE_RESOLVER", ticketResourceResolver);

        plan.registerAuditResourceResolver("GRANT_SERVICE_TICKET_RESOURCE_RESOLVER", new ServiceResourceResolver());
        plan.registerAuditResourceResolver("GRANT_PROXY_TICKET_RESOURCE_RESOLVER", new ServiceResourceResolver());
        plan.registerAuditResourceResolver("VALIDATE_SERVICE_TICKET_RESOURCE_RESOLVER", ticketValidationResourceResolver());

        plan.registerAuditResourceResolver("SAVE_SERVICE_RESOURCE_RESOLVER", returnValueResourceResolver());
        plan.registerAuditResourceResolver("AUTHENTICATION_EVENT_RESOURCE_RESOLVER", nullableReturnValueResourceResolver());

        plan.registerAuditResourceResolver("SERVICE_ACCESS_ENFORCEMENT_RESOURCE_RESOLVER", serviceAccessEnforcementAuditResourceResolver());

        /*
            Add custom resolvers here.
         */
        plan.registerAuditActionResolvers(customAuditActionResolverMap());
        plan.registerAuditResourceResolvers(customAuditResourceResolverMap());
    }
}

DeleteServiceActionResolver.java 

package org.apereo.cas.audit.spi.config;

import org.apereo.inspektr.audit.annotation.Audit;
import org.apereo.inspektr.audit.spi.support.AbstractSuffixAwareAuditActionResolver;
import org.aspectj.lang.JoinPoint;

/**
 * @author: wangsaichao
 * @date: 2018/8/10
 * @description:
 */
public class DeleteServiceActionResolver extends AbstractSuffixAwareAuditActionResolver {

    /**
     * Constructs the resolver with empty values for the two suffixes.
     */
    public DeleteServiceActionResolver() {
        this("","");
    }

    /**
     * Constructs the {@link DeleteServiceActionResolver} with a success suffix and failure
     * suffix.  CANNOT be NULL.
     * @param successSuffix the suffix to use in the event of a success.
     * @param failureSuffix the suffix to use in the event of a failure.
     */
    public DeleteServiceActionResolver(final String successSuffix, final String failureSuffix) {
        super(successSuffix, failureSuffix);
    }

    @Override
    public String resolveFrom(final JoinPoint auditableTarget, final Object retval, final Audit audit) {
        return audit.action() + getSuccessSuffix();
    }

    @Override
    public String resolveFrom(final JoinPoint auditableTarget, final Exception exception, final Audit audit) {
        return audit.action() + getFailureSuffix();
    }

}

DeleteServiceResourceResolver.java 

package org.apereo.cas.audit.spi.config;

import org.apereo.inspektr.audit.spi.AuditResourceResolver;
import org.aspectj.lang.JoinPoint;

/**
 * @author: wangsaichao
 * @date: 2018/8/10
 * @description:
 */
public class DeleteServiceResourceResolver implements AuditResourceResolver {
    @Override
    public String[] resolveFrom(JoinPoint target, Object returnValue) {
        return new String[0];
    }

    @Override
    public String[] resolveFrom(JoinPoint target, Exception exception) {
        return new String[0];
    }
}

最后在resource/META-INFO/spring.factories文件中添加如下: 

org.springframework.boot.autoconfigure.EnableAutoConfiguration=org.apereo.cas.audit.spi.config.CasCoreAuditConfiguration

测试

因为我们配置的是app1.cas.com.启动cas服务端,启动两个客户端,这时访问app1.cas.com是可以登录成功的,使用app2.cas.com登录时未授权的服务.动态添加service之后,就可以了,也可以删除。删除之后,已登录的服务不会强制退出,退出后重新登录,就不能登录了,演示结果如下:
这里写图片描述

 

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

参与评论 您还未登录,请先 登录 后发表或查看评论
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页

打赏作者

weixin_42073629

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值