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

前面我们整合客户端的时候,需要在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添加依赖


    org.apereo.cas
    cas-server-support-jpa-service-registry
    ${cas.version}


    org.apereo.cas
    cas-server-core-services-api
    ${cas.version}


    org.apereo.cas
    cas-server-core-authentication-attributes
    ${cas.version}

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



    4.0.0
    org.apereo.cas
    cas-server-core-audit
    5.3.2
    jar
    cas-server-core-audit
    cas-server-core-audit

    
    
        org.springframework.boot
        spring-boot-starter-parent
        2.0.0.RELEASE
    

    
        5.3.2
    

    
        
            org.springframework.boot
            spring-boot-configuration-processor
            true
        
        
            org.springframework.boot
            spring-boot-autoconfigure
        
        
            org.apereo.cas
            cas-server-core-api-configuration-model
            ${cas.version}
        
        
            org.apereo.cas
            cas-server-core-util-api
            ${cas.version}
        
            org.apereo.cas
            cas-server-core-audit-api
            ${cas.version}
        
        
            org.aspectj
            aspectjrt
            1.9.1
        
        
            javax.servlet
            servlet-api
            2.5
        
    

    
        
            
                org.apache.maven.plugins
                maven-compiler-plugin
                3.5.1
                
                    1.8
                    1.8
                
            
            
            
                maven-source-plugin
                2.1
                
                    true
                
                
                    
                        compile
                        
                            jar
                        
                    
                
            
        
    

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 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 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 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 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 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 resolvers = applicationContext.getBeansOfType(AuditPrincipalIdProvider.class, false, true);
        final List 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之后,就可以了,也可以删除。删除之后,已登录的服务不会强制退出,退出后重新登录,就不能登录了,演示结果如下:

 

你可能感兴趣的:(安全框架,CAS)