前面我们整合客户端的时候,需要在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
为了方便测试,将服务注册只允许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;
}
}
}
这里为了方便直接在地址栏操作增加或删除。代码如下:
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
为了避免重启服务,导致之前的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类型的,没办法,只能写一个一模一样的包了。
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
maven-source-plugin
2.1
true
compile
jar
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());
}
}
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之后,就可以了,也可以删除。删除之后,已登录的服务不会强制退出,退出后重新登录,就不能登录了,演示结果如下: