CAS单点登录:动态添加service(四)
1.简介
在CAS系统中,主要分为三部分,User、Web应用、SSO认证中心。
User就是我们普通用户,Web应用就是需要接入SSO认证中心的应用也就是这里的Service,而SSO认证中心就是CAS服务端。
简单来说就是CAS分为服务端和客户端,而Service就是指具体的多个客户端(CAS Clients)。
我们整合客户端的时候,需要在cas服务端注册,使用的是json文件的方式。不是很方便,这里我们提供接口,动态操作。
2.引入依赖
修改pom.xml,如下:
<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>
<dependency>
<groupId>org.apereo.cas</groupId>
<artifactId>cas-server-support-jdbc</artifactId>
<version>${cas.version}</version>
</dependency>
<dependency>
<groupId>org.apereo.cas</groupId>
<artifactId>cas-server-support-jdbc-drivers</artifactId>
<version>${cas.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.36</version>
</dependency>
排除war包自带的两个json,添加节点:dependentWarExcludes
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.6</version>
<configuration>
<warName>cas</warName>
<failOnMissingWebXml>false</failOnMissingWebXml>
<recompressZippedFiles>false</recompressZippedFiles>
<archive>
<compress>false</compress>
<manifestFile>${manifestFileToUse}</manifestFile>
</archive>
<overlays>
<overlay>
<groupId>org.apereo.cas</groupId>
<artifactId>cas-server-webapp${app.server}</artifactId>
</overlay>
</overlays>
<dependentWarExcludes>
**/services/*.json
</dependentWarExcludes>
</configuration>
</plugin>
3.application.properties添加以下属性
第一次启动使用create-drop,二次运行时改为update
## # Jpa配置 # cas.serviceRegistry.jpa.user=root cas.serviceRegistry.jpa.password=123456 cas.serviceRegistry.jpa.driverClass=com.mysql.jdbc.Driver cas.serviceRegistry.jpa.url=jdbc:mysql://127.0.0.1:3306/cas?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false cas.serviceRegistry.jpa.dialect=org.hibernate.dialect.MySQL5Dialect #连接池配置 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 #create-drop 重启cas服务的时候,就会给干掉 #create 没有表就创建,有就不创建 #none 一直都有 #update 更新 cas.serviceRegistry.jpa.ddlAuto=create-drop
4.添加rest接口
其实主要是使用ServiceManager中的接口,包名:org.apereo.cas.services.ServicesManager
public interface ServicesManager {
RegisteredService save(RegisteredService registeredService);
RegisteredService save(RegisteredService registeredService, boolean publishEvent);
void deleteAll();
RegisteredService delete(long id);
RegisteredService delete(RegisteredService svc);
RegisteredService findServiceBy(String serviceId);
RegisteredService findServiceBy(Service service);
Collection<RegisteredService> findServiceBy(Predicate<RegisteredService> clazz);
<T extends RegisteredService> T findServiceBy(Service serviceId, Class<T> clazz);
<T extends RegisteredService> T findServiceBy(String serviceId, Class<T> clazz);
RegisteredService findServiceBy(long id);
Collection<RegisteredService> getAllServices();
boolean matchesExistingService(Service service);
boolean matchesExistingService(String service);
Collection<RegisteredService> load();
default int count() {
return 0;
}
default Collection<RegisteredService> getServicesForDomain(String domain) {
return this.getAllServices();
}
default Collection<String> getDomains() {
return (Collection)Stream.of("default").collect(Collectors.toList());
}
}
接口的具体实现类:
import com.fdzang.cas.service.domain.ServiceDO;
import com.fdzang.cas.service.framework.ApiResult;
import com.fdzang.cas.service.framework.BaseController;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apereo.cas.services.RegexRegisteredService;
import org.apereo.cas.services.RegisteredService;
import org.apereo.cas.services.ReturnAllAttributeReleasePolicy;
import org.apereo.cas.services.ServicesManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.*;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@Slf4j
@RestController
@RequestMapping("/service")
public class ServiceController extends BaseController {
@Autowired
@Qualifier("servicesManager")
private ServicesManager servicesManager;
@PostMapping
public ApiResult addService(@RequestBody ServiceDO service) throws Exception {
RegisteredService registeredService = findByServiceId(service.getServiceId());
if (registeredService != null) {
return fail("serviceId:" + service.getServiceId() + " 已存在");
}
RegexRegisteredService regexRegisteredService = covertService(service);
servicesManager.save(regexRegisteredService, true);
servicesManager.load();
registeredService = findByServiceId(service.getServiceId());
return ok(covertRegisteredService(registeredService));
}
@DeleteMapping
public ApiResult delService(@RequestParam("serviceId") String serviceId) {
boolean flag = false;
RegisteredService registeredService = findByServiceId(serviceId);
if (registeredService != null) {
try {
servicesManager.delete(registeredService);
} catch (Exception e) {
//这里会报审计错误,直接进行捕获即可,不影响删除逻辑
log.error(e.getMessage());
}
if (null == findByServiceId(serviceId)) {
servicesManager.load();
flag = true;
}
}else{
return fail("serviceId:" + serviceId + " 不存在");
}
if (flag){
return ok("删除成功");
}else{
return fail("删除失败");
}
}
@GetMapping("/all")
public ApiResult getAllService() {
Collection<RegisteredService> allServices = servicesManager.getAllServices();
return ok(covertRegisteredServiceList(allServices));
}
@GetMapping
public ApiResult getByServiceId(@RequestParam("serviceId") String serviceId) {
RegisteredService service = findByServiceId(serviceId);
return ok(covertRegisteredService(service));
}
private ServiceDO covertRegisteredService(RegisteredService registeredService) {
ServiceDO service = new ServiceDO();
service.setServiceId(registeredService.getServiceId());
service.setDescription(registeredService.getDescription());
service.setEvaluationOrder(registeredService.getEvaluationOrder());
service.setId(registeredService.getId());
service.setName(registeredService.getName());
service.setTheme(registeredService.getTheme());
return service;
}
private List<ServiceDO> covertRegisteredServiceList(Collection<RegisteredService> registeredServices) {
if (CollectionUtils.isEmpty(registeredServices)) {
return null;
}
List<ServiceDO> services = new ArrayList<>();
for (RegisteredService registeredService : registeredServices) {
services.add(covertRegisteredService(registeredService));
}
return services;
}
private RegexRegisteredService covertService(ServiceDO service) throws Exception {
RegexRegisteredService regexRegisteredService = new RegexRegisteredService();
String serviceId = "^(https|imaps|http)://" + service.getServiceId() + ".*";
ReturnAllAttributeReleasePolicy returnAllAttributeReleasePolicy = new ReturnAllAttributeReleasePolicy();
regexRegisteredService.setServiceId(serviceId);
regexRegisteredService.setId(service.getId());
regexRegisteredService.setDescription(service.getDescription());
regexRegisteredService.setEvaluationOrder(service.getEvaluationOrder());
if (StringUtils.isNotBlank(service.getTheme())) {
regexRegisteredService.setTheme(service.getTheme());
}
regexRegisteredService.setAttributeReleasePolicy(returnAllAttributeReleasePolicy);
regexRegisteredService.setName(service.getName());
regexRegisteredService.setLogoutUrl(new URL("http://" + service.getServiceId()));
return regexRegisteredService;
}
public RegisteredService findByServiceId(String serviceId){
RegisteredService service = null;
serviceId = "http://" + serviceId;
try {
service = servicesManager.findServiceBy(serviceId);
} catch (Exception e) {
log.error(e.getMessage());
}
return service;
}
}
这个地方,我自定义了ServiceDO用来数据的接收及展示。
自定义了ApiResult,统一返回结果。
5.添加包扫描配置
cas项目,其实也是集成的Springboot,这里我们自定义注解完成包扫描工作,后续新的类加进来,无需再修改spring.factories
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan("com.fdzang.cas")
public class SpringConfig {
}
修改spring.factories,加入我们的包扫描配置。
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.apereo.cas.config.CasEmbeddedContainerTomcatConfiguration,\ org.apereo.cas.config.CasEmbeddedContainerTomcatFiltersConfiguration,\ com.fdzang.cas.service.config.SpringConfig
参考:https://blog.csdn.net/qq_34021712/article/details/81638090


浙公网安备 33010602011771号