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