Sentinel
原理
Sentinel 是阿里中间件团队开源的,面向分布式服务架构的轻量级高可用流量控制组件,主要以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度来帮助用户保护服务的稳定性。
sentinel-dashboard,Sentinel的可视化界面,通过 Sentinel 的控制台,我们可以对规则进行查询和修改,也可以查看到实时监控,机器列表等信息
SSO
原理
单点登录(SingleSignOn,SSO),就是通过用户的一次性鉴别登录。当用户在身份认证服务器上登录一次以后,即可获得访问单点登录系统中其他关联系统和应用软件的权限,同时这种实现是不需要管理员对用户的登录状态或其他信息进行修改的,这意味着在多个应用系统中,用户只需一次登录就可以访问所有相互信任的应用系统。从用户角度看,告别了多个IP分别验证的繁琐,体验一键式登录的便捷;
从开发角度,SSO为开发人员提供一个通用的身份验证框架,提高了开发效率。
CAS(Central Authentication Service ),中央认证服务,一种独立开放指令协议,是 Yale 大学发起的一个企业级开源项目,旨在为 Web 应用系统提供一种可靠的 SSO 解决方案。
cas server,CAS框架提供,用来提供认证服务,处理cas-client端发送的请求。
cas client,CAS框架提供,建立与cas-server端的连接,向cas-server发送请求。
参考博文:集成基于CAS协议的单点登陆
开发工具
IntelliJ IDEA 2020.1.3 x64
Jdk-1.8
源码下载地址
开发步骤
一、cas-server端
- 确定CAS版本
参考博文:cas与jdk版本选择
目前最高版本是cas 6.2.x ,需要JDK 11,
由于开发环境是jdk1.8,所以选择了cas5.3版本;
sentinel选择了1.7.2版本,较稳定
2.cas打包
打开cas源码,在上方输入cmd打开dos命令行窗口,输入mvn clean package,执行完毕后,在target目录下生成war包
- 修改cas的配置文件
cas默认只支持https访问,需要添加http访问支持
url:cas\WEB-INF\classes\services\HTTPSandIMAPS-10000001.json
cas默认账号密码修改地址:cas\WEB-INF\classes\application.properties
- 启动cas server并访问
把war包copy到tomcat8\webapps下面,直接启动startup.bat
访问url:http://localhost:8443/cas
注销url:http://localhost:8080/cas/logout
参考博文:CAS5.3服务器搭建及SpringBoot整合CAS实现单点登录
二、cas-client端
- sentinel源码pom.xml中 添加cas客户端依赖包
<dependency>
<groupId>org.jasig.cas.client</groupId>
<artifactId>cas-client-core</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>net.unicon.cas</groupId>
<artifactId>cas-client-autoconfig-support</artifactId>
<version>2.3.0-GA</version>
</dependency>
- Sentinel源码application.properties文件中增加配置
#cas服务端的地址
cas.server-url-prefix=http://localhost:8443/cas
#cas服务端的登录地址
cas.server-login-url=http://localhost:8443/cas/login
#当前服务器的地址(客户端)
cas.client-host-url=http://localhost:444/
#Ticket校验器使用Cas30ProxyReceivingTicketValidationFilter
cas.validation-type=cas3
cas.use-session=true
#自定义的忽略url
casIgnorePattern=/,/auth/toLogin,/version,/auth/login
- 编写一个config类,加载单点登录的关键过滤器
@Configuration
public class CasConfig implements WebMvcConfigurer {
@Value("${cas.server-url-prefix}")
private String casServerUrlPrefix;
@Value("${cas.server-login-url}")
private String casServerLoginUrl;
@Value("${cas.client-host-url}")
private String clientHostUrl;
/**
* 注入单点登录过滤器
* @return AuthenticationFilter
*/
@Bean
public AuthenticationFilter authenticationFilter() {
return new AuthenticationFilter();
}
/**
* 注入单点登出过滤器
* @return SingleSignOutFilter
*/
@Bean
public SingleSignOutFilter singleSignOutFilter() {
return new SingleSignOutFilter();
}
/**
* 注入单点登出监听器
* @return SingleSignOutHttpSessionListener
*/
@Bean
public SingleSignOutHttpSessionListener singleSignOutHttpSessionListener() {
return new SingleSignOutHttpSessionListener();
}
/**
* 加载首页
* @param registry
*/
@Override
public void addViewControllers(ViewControllerRegistry registry) {
//首页
registry.addViewController("/").setViewName("forward:/index.htm");
}
/**
* 配置登出过滤器
* @return SingleSignOutFilter
*/
@Bean
public FilterRegistrationBean<SingleSignOutFilter> logOutFilter() {
FilterRegistrationBean<SingleSignOutFilter> authenticationFilter = new FilterRegistrationBean();
authenticationFilter.setFilter(singleSignOutFilter());
authenticationFilter.setEnabled(true);
Map<String, String> initParameters = new HashMap<String, String>();
initParameters.put("casServerUrlPrefix", casServerUrlPrefix);
authenticationFilter.setInitParameters(initParameters);
authenticationFilter.addUrlPatterns("/*");
//必须先加载登出过滤器
authenticationFilter.setOrder(Integer.parseInt(DataType.ORDER_ONE.getDataType()));
return authenticationFilter;
}
/**
* 配置监听器
* @return SingleSignOutHttpSessionListener
*/
@Bean
public ServletListenerRegistrationBean<SingleSignOutHttpSessionListener> singleSignOutHttpSessionListenerBean() {
ServletListenerRegistrationBean<SingleSignOutHttpSessionListener> listenerRegistrationBean = new ServletListenerRegistrationBean<>();
listenerRegistrationBean.setEnabled(true);
listenerRegistrationBean.setListener(singleSignOutHttpSessionListener());
listenerRegistrationBean.setOrder(Integer.parseInt(DataType.ORDER_TWO.getDataType()));
return listenerRegistrationBean;
}
/**
* 配置授权过滤器
* @return FilterRegistrationBean
*/
@Bean
public FilterRegistrationBean authenticationFilterRegistrationBean() {
FilterRegistrationBean authenticationFilter = new FilterRegistrationBean();
authenticationFilter.setFilter(authenticationFilter());
Map<String, String> initParameters = new HashMap<String, String>();
initParameters.put("casServerLoginUrl", casServerLoginUrl);
//域名换成ip,不然单点退出失效
initParameters.put("serverName", clientHostUrl);
initParameters.put("ignorePattern", casIgnorePattern);
authenticationFilter.setInitParameters(initParameters);
authenticationFilter.setOrder(Integer.parseInt(DataType.ORDER_TWO.getDataType()));
List<String> urlPatterns = new ArrayList<String>();
// 设置匹配的url
urlPatterns.add("/*");
authenticationFilter.setUrlPatterns(urlPatterns);
return authenticationFilter;
}
对以上代码进行说明:
1) SingleSignOutFilter必须第一个加载,授权过滤器的order设置为3,会导致白名单配置失效
参考博文:CAS单点登录学习笔记–SpringBoot+CAS Client 单点退出(二)
2)忽略url必须配置,不然单点注销失效
//域名换成ip,不然单点退出失效
initParameters.put("serverName", clientHostUrl);
initParameters.put("ignorePattern", casIgnorePattern);
- 启动类加入开启cas client的注解
@EnableCasClient
@SpringBootApplication
public class DashboardApplication {
public static void main(String[] args) {
triggerSentinelInit();
SpringApplication.run(DashboardApplication.class, args);
}
private static void triggerSentinelInit() {
new Thread(() -> InitExecutor.doInit()).start();
}
}
- 启动项目测试
http://localhost:444
跳转逻辑梳理
- 输入http://localhost:444
- 302重定向到cas-server端
Request URL: https://sso.server.com:8443/cas/login?service=https%3A%2F%2F127.0.0.1%3A444%2F
- 输入账号密码验证通过,拿到ticket,再次302
- sentinel做出响应,进到系统中
总结:
实现了通过cas认证进入sentinel系统的功能,以上有问题,欢迎指正。
(截图是实现了https访问的截图,http与此类似,懒得切换到http截图)