转载地址: https://blog.csdn.net/Anumbrella/article/details/82728641
# 文档地址
https://apereo.github.io/cas
# 下载地址
https://github.com/apereo/cas-overlay-template/tree/5.3
# idea 编辑
建立 src/main/java、src/main/resources、src/main/resources/services 文件夹
# 拷贝配置文件
1.拷贝 target/cas/WEB-INF/classes/application.properties 文件到 src/main/resources
2.拷贝 target/cas/WEB-INF/classes/services/HTTPSandIMAPS-10000001.json 文件到 src/main/resources/services,添加 http
org.apereo.cas
cas-server-support-json-service-registry
${cas.version}
# 开启识别Json文件,默认false
cas.serviceRegistry.initFromJson=true
#自动扫描服务配置,默认开启
cas.serviceRegistry.watcherEnabled=true
#120秒扫描一遍
cas.serviceRegistry.schedule.repeatInterval=120000
#延迟15秒开启
# cas.serviceRegistry.schedule.startDelay=15000
cas.serviceRegistry.json.location=classpath:/services
# 服务重定向
cas.logout.followServiceRedirects=true
org.apereo.cas
cas-server-support-jdbc
${cas.version}
mysql
mysql-connector-java
5.1.34
CREATE DATABASE cas;
USE cas;
CREATE TABLE `sys_user` (
`id` VARCHAR(20) NOT NULL,
`username` VARCHAR(100) NOT NULL,
`password` VARCHAR(100) NOT NULL,
PRIMARY KEY (`id`)
)
ENGINE=InnoDB;
cas.authn.jdbc.query[0].user=root
cas.authn.jdbc.query[0].password=root
cas.authn.jdbc.query[0].driverClass=com.mysql.jdbc.Driver
cas.authn.jdbc.query[0].url=jdbc:mysql://192.168.1.24:3306/cas?useUnicode=true&characterEncoding=utf-8
cas.authn.jdbc.query[0].dialect=org.hibernate.dialect.MySQLDialect
cas.authn.jdbc.query[0].sql=select * from sys_user where username=?
cas.authn.jdbc.query[0].fieldPassword=password
# 0正常,1需要修改密码
cas.authn.jdbc.query[0].fieldExpired=expired
# 0正常,1账户被禁用,无法登陆
cas.authn.jdbc.query[0].fieldDisabled=disabled
#cas.authn.accept.users=casuser::Mellon
cas.authn.jdbc.query[0].passwordEncoder.type=DEFAULT
cas.authn.jdbc.query[0].passwordEncoder.characterEncoding=UTF-8
cas.authn.jdbc.query[0].passwordEncoder.encodingAlgorithm=MD5
package com.vim.sso;
import org.springframework.security.crypto.password.PasswordEncoder;
public class MyPasswordEncoder implements PasswordEncoder {
@Override
public String encode(CharSequence charSequence) {
//charSequence 为用户输入的密码
return charSequence.toString();
}
@Override
public boolean matches(CharSequence charSequence, String str) {
//charSequence 为用户输入的密码
System.out.println(charSequence);
//str 为数据库密码
System.out.println(str);
return true;
}
}
cas.authn.jdbc.query[0].passwordEncoder.type=com.vim.sso.MyPasswordEncoder
org.apereo.cas
cas-server-core-authentication-api
${cas.version}
org.apereo.cas
cas-server-core-configuration-api
${cas.version}
CustomUsernamePasswordAuthentication
package com.vim.sso;
import org.apereo.cas.authentication.*;
import org.apereo.cas.authentication.handler.support.AbstractPreAndPostProcessingAuthenticationHandler;
import org.apereo.cas.authentication.handler.support.AbstractUsernamePasswordAuthenticationHandler;
import org.apereo.cas.authentication.principal.PrincipalFactory;
import org.apereo.cas.services.ServicesManager;
import java.security.GeneralSecurityException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class CustomUsernamePasswordAuthentication extends AbstractPreAndPostProcessingAuthenticationHandler {
public CustomUsernamePasswordAuthentication(String name, ServicesManager servicesManager, PrincipalFactory principalFactory, Integer order) {
super(name, servicesManager, principalFactory, order);
}
@Override
public boolean supports(Credential credential) {
//判断传递过来的Credential 是否是自己能处理的类型
return credential instanceof CustomCredential;
}
@Override
protected AuthenticationHandlerExecutionResult doAuthentication(Credential credential) throws GeneralSecurityException, PreventedException {
CustomCredential customCredential = (CustomCredential) credential;
String username = customCredential.getUsername();
String password = customCredential.getPassword();
String telephone = customCredential.getTelephone();
System.out.println("******CustomUsernamePasswordAuthentication******:" + username);
System.out.println("******CustomUsernamePasswordAuthentication******:" + password);
System.out.println("******CustomUsernamePasswordAuthentication******:" + telephone);
Map returnInfo = new HashMap<>();
returnInfo.put("aName", "aValue");
returnInfo.put("bName", "bValue");
final List list = new ArrayList<>();
return createHandlerResult(credential,
this.principalFactory.createPrincipal(username, returnInfo), list);
}
}
package com.vim.sso;
import org.apereo.cas.authentication.AuthenticationEventExecutionPlan;
import org.apereo.cas.authentication.AuthenticationEventExecutionPlanConfigurer;
import org.apereo.cas.authentication.AuthenticationHandler;
import org.apereo.cas.authentication.principal.DefaultPrincipalFactory;
import org.apereo.cas.services.ServicesManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration("CustomAuthenticationConfiguration")
public class CustomAuthenticationConfiguration implements AuthenticationEventExecutionPlanConfigurer {
@Autowired
@Qualifier("servicesManager")
private ServicesManager servicesManager;
@Bean
public AuthenticationHandler myAuthenticationHandler() {
// 参数: name, servicesManager, principalFactory, order
// 定义为优先使用它进行认证
return new CustomUsernamePasswordAuthentication(CustomUsernamePasswordAuthentication.class.getName(),
servicesManager, new DefaultPrincipalFactory(), 1);
}
@Override
public void configureAuthenticationExecutionPlan(final AuthenticationEventExecutionPlan plan) {
plan.registerAuthenticationHandler(myAuthenticationHandler());
}
}
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.vim.sso.CustomAuthenticationConfiguration
org.apereo.cas
cas-server-core-webflow
${cas.version}
org.apereo.cas
cas-server-core-webflow-api
${cas.version}
{
"@class" : "org.apereo.cas.services.RegexRegisteredService",
"serviceId" : "^(https|imaps|http)://.*",
"name" : "web",
"id" : 10000001,
"evaluationOrder" : 10,
"accessStrategy" : {
"@class" : "org.apereo.cas.services.DefaultRegisteredServiceAccessStrategy",
"enabled" : true,
"ssoEnabled" : true
},
"theme": "customTheme"
}
# 开启识别Json文件,默认false
cas.serviceRegistry.initFromJson=true
#自动扫描服务配置,默认开启
cas.serviceRegistry.watcherEnabled=true
#120秒扫描一遍
cas.serviceRegistry.schedule.repeatInterval=120000
#延迟15秒开启
# cas.serviceRegistry.schedule.startDelay=15000
cas.serviceRegistry.json.location=classpath:/services
cas.theme.defaultThemeName=customTheme
customTheme.javascript.file=/themes/customTheme/js/cas.js
customTheme.standard.css.file=/themes/customTheme/css/cas.css
customTheme.login.images.path=/themes/customTheme/images
cas.standard.css.file=/css/cas.css
cas.javascript.file=/js/cas.js
cas.admin.css.file=/css/admin.css
# 静态资源文件
resources/static/themes/customTheme/css/cas.css
resources/static/themes/customTheme/js/cas.js
resources/static/themes/customTheme/images/
# 登录页面
resources/templates/customTheme/casLoginView.html
package com.vim.sso;
import org.apereo.cas.configuration.CasConfigurationProperties;
import org.apereo.cas.web.flow.CasWebflowConstants;
import org.apereo.cas.web.flow.configurer.AbstractCasWebflowConfigurer;
import org.springframework.context.ApplicationContext;
import org.springframework.webflow.definition.registry.FlowDefinitionRegistry;
import org.springframework.webflow.engine.Flow;
import org.springframework.webflow.engine.ViewState;
import org.springframework.webflow.engine.builder.BinderConfiguration;
import org.springframework.webflow.engine.builder.support.FlowBuilderServices;
/**
* @author anumbrella
*/
public class CustomWebflowConfigurer extends AbstractCasWebflowConfigurer {
public CustomWebflowConfigurer(FlowBuilderServices flowBuilderServices,
FlowDefinitionRegistry flowDefinitionRegistry,
ApplicationContext applicationContext,
CasConfigurationProperties casProperties) {
super(flowBuilderServices, flowDefinitionRegistry, applicationContext, casProperties);
}
@Override
protected void doInitialize() {
final Flow flow = super.getLoginFlow();
bindCredential(flow);
}
/**
* 绑定自定义的Credential信息
*
* @param flow
*/
protected void bindCredential(Flow flow) {
// 重写绑定自定义credential
// 重写绑定自定义credential
createFlowVariable(flow, CasWebflowConstants.VAR_ID_CREDENTIAL, CustomCredential.class);
// 登录页绑定新参数
final ViewState state = (ViewState) flow.getState(CasWebflowConstants.STATE_ID_VIEW_LOGIN_FORM);
final BinderConfiguration cfg = getViewStateBinderConfiguration(state);
// 由于用户名以及密码已经绑定,所以只需对新加系统参数绑定即可
// 字段名,转换器,是否必须字段
cfg.addBinding(new BinderConfiguration.Binding("telephone", null, true));
}
}
package com.vim.sso;
import org.apereo.cas.authentication.UsernamePasswordCredential;
public class CustomCredential extends UsernamePasswordCredential {
private String telephone;
public String getTelephone() {
return telephone;
}
public void setTelephone(String telephone) {
this.telephone = telephone;
}
}
package com.vim.sso;
import org.apereo.cas.configuration.CasConfigurationProperties;
import org.apereo.cas.web.flow.CasWebflowConfigurer;
import org.apereo.cas.web.flow.CasWebflowExecutionPlan;
import org.apereo.cas.web.flow.CasWebflowExecutionPlanConfigurer;
import org.apereo.cas.web.flow.config.CasWebflowContextConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.webflow.definition.registry.FlowDefinitionRegistry;
import org.springframework.webflow.engine.builder.support.FlowBuilderServices;
@Configuration("customerAuthWebflowConfiguration")
@EnableConfigurationProperties(CasConfigurationProperties.class)
public class CustomerAuthWebflowConfiguration implements CasWebflowExecutionPlanConfigurer {
@Autowired
private CasConfigurationProperties casProperties;
@Autowired
@Qualifier("loginFlowRegistry")
private FlowDefinitionRegistry loginFlowDefinitionRegistry;
@Autowired
private ApplicationContext applicationContext;
@Autowired
private FlowBuilderServices flowBuilderServices;
@Bean
public CasWebflowConfigurer customWebflowConfigurer() {
// 实例化自定义的表单配置类
final CustomWebflowConfigurer c = new CustomWebflowConfigurer(flowBuilderServices, loginFlowDefinitionRegistry,
applicationContext, casProperties);
// 初始化
c.initialize();
// 返回对象
return c;
}
@Override
public void configureWebflowExecutionPlan(final CasWebflowExecutionPlan plan) {
plan.registerWebflowConfigurer(customWebflowConfigurer());
}
}
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.vim.sso.CustomAuthenticationConfiguration,com.vim.sso.CustomerAuthWebflowConfiguration
org.jasig.cas.client
cas-client-core
3.5.0
customCas.server-url-prefix=http://www.testserver.com:8080/cas
customCas.server-login-url=http://www.testserver.com:8080/cas/login
customCas.client-host-url=http://localhost:8081
customCas.client-ignore-url=/a/*,/b/*
package com.vim.common.config;
import org.jasig.cas.client.authentication.UrlPatternMatcherStrategy;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
public class SimpleUrlPatternMatcherStrategy implements UrlPatternMatcherStrategy {
private List patternList = new ArrayList<>();
/**
* description:判断是否匹配这个字符串
*
* @param: [url]用户请求的连接
* @return: true:不需要拦截
* false:必须要登录
*/
@Override
public boolean matches(String url) {
//使用正则表达式来匹配需要忽略的连接
boolean flag = false;
for(Pattern pattern:patternList){
if(pattern.matcher(url).find()){
flag = true;
break;
}
}
return flag;
}
/**
* description:正则表达式的规则,该规则在配置AuthenticationFilter的ignorePattern中设置
*
* @param: [pattern]
* @return: void
*/
@Override
public void setPattern(String pattern) {
String[] patternArr = pattern.split(",");
for(String s:patternArr){
patternList.add(Pattern.compile(s.trim()));
}
}
}
package com.vim.common.config;
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.HttpServletRequestWrapperFilter;
import org.jasig.cas.client.validation.Cas30ProxyReceivingTicketValidationFilter;
import org.springframework.beans.factory.annotation.Value;
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 java.util.EventListener;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class CasConfig {
@Value("${customCas.server-url-prefix}")
private String CAS_SERVER_URL_PREFIX;
@Value("${customCas.server-login-url}")
private String CAS_SERVER_URL_LOGIN;
@Value("${customCas.client-host-url}")
private String CAS_CLIENT_URL_HOST;
@Value("${customCas.client-ignore-url}")
private String CAS_CLIENT_URL_IGNORE;
/**
* description: 登录过滤器
* @param: []
* @return: org.springframework.boot.web.servlet.FilterRegistrationBean
*/
@Bean
public FilterRegistrationBean filterSingleRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new SingleSignOutFilter());
// 设定匹配的路径
registration.addUrlPatterns("/*");
Map initParameters = new HashMap<>();
initParameters.put("casServerUrlPrefix", CAS_SERVER_URL_PREFIX);
registration.setInitParameters(initParameters);
// 设定加载的顺序
registration.setOrder(1);
return registration;
}
/**
* description:过滤验证器
* * @param: []
* @return: org.springframework.boot.web.servlet.FilterRegistrationBean
*/
@Bean
public FilterRegistrationBean filterValidationRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new Cas30ProxyReceivingTicketValidationFilter());
// 设定匹配的路径
registration.addUrlPatterns("/*");
Map initParameters = new HashMap<>();
initParameters.put("casServerUrlPrefix", CAS_SERVER_URL_PREFIX);
initParameters.put("serverName", CAS_CLIENT_URL_HOST);
initParameters.put("useSession", "true");
registration.setInitParameters(initParameters);
// 设定加载的顺序
registration.setOrder(1);
return registration;
}
/**
* description:授权过滤器
* @param: []
* @return: org.springframework.boot.web.servlet.FilterRegistrationBean
*/
@Bean
public FilterRegistrationBean filterAuthenticationRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new AuthenticationFilter());
// 设定匹配的路径
registration.addUrlPatterns("/*");
Map initParameters = new HashMap<>();
initParameters.put("casServerLoginUrl", CAS_SERVER_URL_LOGIN);
initParameters.put("serverName", CAS_CLIENT_URL_HOST);
//忽略/logout的路径
initParameters.put("ignorePattern", CAS_CLIENT_URL_IGNORE);
initParameters.put("ignoreUrlPatternType", SimpleUrlPatternMatcherStrategy.class.getName());
registration.setInitParameters(initParameters);
// 设定加载的顺序
registration.setOrder(1);
return registration;
}
/**
* wraper过滤器
* @return
*/
@Bean
public FilterRegistrationBean filterWrapperRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new HttpServletRequestWrapperFilter());
// 设定匹配的路径
registration.addUrlPatterns("/*");
// 设定加载的顺序
registration.setOrder(1);
return registration;
}
/**
* 添加监听器
* @return
*/
@Bean
public ServletListenerRegistrationBean singleSignOutListenerRegistration(){
ServletListenerRegistrationBean registrationBean = new ServletListenerRegistrationBean();
registrationBean.setListener(new SingleSignOutHttpSessionListener());
registrationBean.setOrder(1);
return registrationBean;
}
}