Java -- springboot 配置 cas 服务器

转载地址: https://blog.csdn.net/Anumbrella/article/details/82728641

1、下载 CAS

# 文档地址
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

2、配置依赖

  • pom.xml

    org.apereo.cas
    cas-server-support-json-service-registry
    ${cas.version}
  • application.properties
# 开启识别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

3、开启 jdbc 验证

  • 配置依赖

    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;
  • 修改 application.properties
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

4、添加MD5加密配置

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

5、自定义密码策略

  • 密码类
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;
    }
}
  • application.properties
cas.authn.jdbc.query[0].passwordEncoder.type=com.vim.sso.MyPasswordEncoder

6、自定义密码策略(自定义数据源查询方式)

  • 添加依赖


    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());
    }
}
  • resources 下创建META-INF文件夹,并创建spring.factories文件
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.vim.sso.CustomAuthenticationConfiguration

7、自定义登录页面

  • 添加依赖

    org.apereo.cas
    cas-server-core-webflow
    ${cas.version}


    org.apereo.cas
    cas-server-core-webflow-api
    ${cas.version}
  • 注册 json,resources 下创建 services/web-10000001.json,主题名称为 customTheme
{
  "@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"
}
  • application.properties 开启json扫码
# 开启识别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
  • resources 下创建customTheme.properties文件
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

8、添加自定义字段

  • CustomWebflowConfigurer
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));

    }
}
  • CustomCredential
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;
    }
}
  • CustomerAuthWebflowConfiguration
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());
    }
}
  • spring.factories 文件修改
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.vim.sso.CustomAuthenticationConfiguration,com.vim.sso.CustomerAuthWebflowConfiguration

9、springboot 配置

  • pom依赖

  org.jasig.cas.client
  cas-client-core
  3.5.0
  • application.properties
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/*
  • url 匹配策略 SimpleUrlPatternMatcherStrategy
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()));
        }
    }
}
  • casConfig 配置
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;
    }

}

 

 

 

你可能感兴趣的:(SpringBoot)