CAS单点登录:集成客户端,自定义client-starter(二)
0.说明
本系列文章只根据自己的需要做部分定制,完整的教程见:https://blog.csdn.net/qq_34021712/category_9278675.html
有兴趣的可以一起研究。
1.服务端
1.1.Service配置
客户端接入 CAS 首先需要在服务端进行注册,否则客户端访问将提示“未认证授权的服务”警告:
简单需求:对所有https和http请求的service进行允许认证。
在resources/services下新建文件fdzang-1000.json,这个文件是我根据cas源代码HTTPSandIMAPS-10000001.json更改的。路径:cas\WEB-INF\classes\services
{ "@class": "org.apereo.cas.services.RegexRegisteredService", "serviceId": "^(https|imaps|http)://.*", "name": "fdzang", "id": 1000, "description": "CAS-SSO 登入", "evaluationOrder": 10000 }
注意:
services目录中可包含多个 JSON 文件,其命名必须:${name}-${id}.json,id必须为json文件中内容id一致
对其中属性的说明如下,更多详细内容见:官方文档-Service-Management。
- @class:必须为org.apereo.cas.services.RegisteredService的实现类
- serviceId:对服务进行描述的表达式,可用于匹配一个或多个 URL 地址
- name: 服务名称
- id:全局唯一标志
- description:服务描述,会显示在默认登录页
- evaluationOrder:定义多个服务的执行顺序
1.2.修改application.properties
配置好service之后,根据官方文档-service-registry,还需修改 application.properties 文件告知 CAS 服务端从本地加载服务定义文件
# 注册客户端
cas.serviceRegistry.initFromJson=true
2.自定义client-starter
2.1.创建项目
创建一个springboot项目,pom.xml文件如下:
<?xml version="1.0" encoding="UTF-8"?> <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>com.fdzang</groupId> <artifactId>cas-client-spring-boot-starter</artifactId> <version>1.0-SNAPSHOT</version> <!-- 引用依赖的父包 --> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.9.RELEASE</version> </parent> <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-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-autoconfigure</artifactId> </dependency> <dependency> <groupId>org.jasig.cas.client</groupId> <artifactId>cas-client-core</artifactId> <version>3.5.0</version> </dependency> <dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>1.1.0.Final</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </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>
2.2.加载配置文件
这个类主要的作用是读取client端application.yml中,关于cas相关的配置
import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import javax.validation.constraints.NotNull; @Data @ConfigurationProperties(prefix = "cas", ignoreUnknownFields = false) public class CasClientConfigurationProperties { /** * CAS 服务端 url 不能为空 */ @NotNull private String serverUrlPrefix; /** * CAS 服务端登录地址 上面的连接 加上/login 该参数不能为空 */ @NotNull private String serverLoginUrl; /** * 当前客户端的地址 */ @NotNull private String serverName; /** * 忽略规则,访问那些地址 不需要登录 */ private String ignorePattern; /** * 认证的URL */ private String authrizationUrl; }
2.3.编写AutoConfigure配置类
这些自动注入的配置,能够让客户端实现接入cas。
import org.jasig.cas.client.authentication.AuthenticationFilter; import org.jasig.cas.client.session.SingleSignOutFilter; import org.jasig.cas.client.session.SingleSignOutHttpSessionListener; import org.jasig.cas.client.util.AssertionThreadLocalFilter; import org.jasig.cas.client.util.HttpServletRequestWrapperFilter; import org.jasig.cas.client.validation.Cas30ProxyReceivingTicketValidationFilter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.boot.web.servlet.ServletListenerRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.util.StringUtils; import java.util.EventListener; import java.util.HashMap; import java.util.Map; @Configuration @EnableConfigurationProperties(CasClientConfigurationProperties.class) public class CasClientConfiguration { @Autowired CasClientConfigurationProperties configProps; @Bean public FilterRegistrationBean filterSingleRegistration() { final FilterRegistrationBean registration = new FilterRegistrationBean(); registration.setFilter(new SingleSignOutFilter()); registration.addUrlPatterns("/*"); registration.setOrder(1); Map<String, String> params = new HashMap<String, String>(); params.put("casServerUrlPrefix", configProps.getServerUrlPrefix()); params.put("serverName", configProps.getServerName()); registration.setInitParameters(params); return registration; } @Bean public ServletListenerRegistrationBean<EventListener> singleSignOutListenerRegistration() { ServletListenerRegistrationBean<EventListener> registrationBean = new ServletListenerRegistrationBean<EventListener>(); registrationBean.setListener(new SingleSignOutHttpSessionListener()); registrationBean.setOrder(1); return registrationBean; } @Bean public FilterRegistrationBean filterAuthenticationRegistration() { final FilterRegistrationBean registration = new FilterRegistrationBean(); registration.setFilter(new AuthenticationFilter()); registration.addUrlPatterns("/*"); registration.setOrder(2); Map<String, String> params = new HashMap<String, String>(); params.put("casServerLoginUrl", configProps.getServerLoginUrl()); params.put("serverName", configProps.getServerName()); if (!StringUtils.isEmpty(configProps.getIgnorePattern())) { params.put("ignorePattern", configProps.getIgnorePattern()); } registration.setInitParameters(params); return registration; } @Bean public FilterRegistrationBean filterValidationRegistration() { final FilterRegistrationBean registration = new FilterRegistrationBean(); registration.setFilter(new Cas30ProxyReceivingTicketValidationFilter()); registration.addUrlPatterns("/*"); registration.setOrder(3); Map<String, String> params = new HashMap<String, String>(); params.put("casServerUrlPrefix", configProps.getServerUrlPrefix()); params.put("serverName", configProps.getServerName()); params.put("useSession", "true"); registration.setInitParameters(params); return registration; } @Bean public FilterRegistrationBean filterWrapperRegistration() { final FilterRegistrationBean registration = new FilterRegistrationBean(); registration.setFilter(new HttpServletRequestWrapperFilter()); registration.addUrlPatterns("/*"); registration.setOrder(4); return registration; } @Bean public FilterRegistrationBean casAssertionThreadLocalFilter() { FilterRegistrationBean registration = new FilterRegistrationBean(); registration.setFilter(new AssertionThreadLocalFilter()); registration.addUrlPatterns("/*"); registration.setOrder(5); return registration; } }
2.4.编译基于注解启动方式
客户端只需要在启动类上加上@EnableCasClient注解即可实现接入cas
import org.springframework.context.annotation.Import; import java.lang.annotation.*; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @Import(CasClientConfiguration.class) public @interface EnableCasClient { }
3.客户端
3.1.新建项目
新建一个springboot项目,pom.xml文件如下:
<?xml version="1.0" encoding="UTF-8"?> <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>com.fdzang</groupId> <artifactId>cas-client</artifactId> <version>1.0-SNAPSHOT</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.9.RELEASE</version> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <java.cas.client.version>3.5.0</java.cas.client.version> </properties> <dependencies> <dependency> <groupId>com.fdzang</groupId> <artifactId>cas-client-spring-boot-starter</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies> </project>
3.2.配置文件application.yml
server:
port: 8082
cas:
server-url-prefix: https://server.cas.com:8443/cas
server-login-url: https://server.cas.com:8443/cas/login
server-name: http://127.0.0.1:8082
3.3.主启动类
import com.fdzang.cas.client.configuration.EnableCasClient; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication @EnableCasClient public class ClientApplication { public static void main(String[] args) { SpringApplication.run(ClientApplication.class, args); } }
3.4.测试接口
import com.fdzang.cas.client.configuration.CasClientConfigurationProperties; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @RestController public class UserController { @Autowired CasClientConfigurationProperties configProps; @GetMapping("/login") public String login(HttpServletRequest request, HttpServletResponse response) throws IOException { String username = request.getRemoteUser(); return username; } @GetMapping("/logout") public void loginOut(HttpServletRequest request, HttpServletResponse response) throws IOException { String url = configProps.getServerUrlPrefix() + "/logout?service=" + configProps.getServerName(); response.sendRedirect(url); } }