cas官方给出了自定义配置的方法,详情可以参考cas配置扩展
package org.apereo.cas.custom.config;
@Configuration
@EnableConfigurationProperties(CasConfigurationProperties.class)
public class CustomCasConfiguration {
// todo 将自己的配置类注册到容器
}
这里需要先引入maven依赖
<!--配置信息-->
<dependency>
<groupId>org.apereo.cas</groupId>
<artifactId>cas-server-core-configuration-api</artifactId>
<version>${cas.version}</version>
</dependency>
官方推荐新增配置文件如下
src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
内容为自己建立的配置类的包路径
但是我们使用的spring boot版本是1.5.18,不支持这种配置形式
直接在resources目录下新建目录,MEATA-INF,然后新增一个spring.factories文件即可
文件内容为
org.springframework.boot.autoconfigure.EnableAutoConfiguration=org.apereo.cas.custom.config.CustomCasConfiguration
官方帮我们默认实现了很多认证方法可以参考自定义认证方法,根据自己的需要选择即可,官方文档中已经明确告诉我们各个认证方法的引入及配置方式了,就不再赘述
如果官方提供的方法都不能满足我们的需求,那么就可以自定义认证方法,可以参考cas自定义认证策略
引入maven包
<dependency>
<groupId>org.apereo.cas</groupId>
<artifactId>cas-server-core-authentication-api</artifactId>
<version>${cas.version}</version>
</dependency>
定义自己的配置类,这里需要注意,这里有一个order的参数,这个参数设置了authenticationHandler的执行顺序,不要设置两个相同的order
package org.apereo.cas.custom.handler;
import org.apereo.cas.authentication.AuthenticationHandlerExecutionResult;
import org.apereo.cas.authentication.MessageDescriptor;
import org.apereo.cas.authentication.PreventedException;
import org.apereo.cas.authentication.UsernamePasswordCredential;
import org.apereo.cas.authentication.handler.support.AbstractUsernamePasswordAuthenticationHandler;
import org.apereo.cas.authentication.principal.PrincipalFactory;
import org.apereo.cas.services.ServicesManager;
import javax.security.auth.login.FailedLoginException;
import java.security.GeneralSecurityException;
import java.util.ArrayList;
import java.util.List;
public class CustomAuthenticationHandler extends AbstractUsernamePasswordAuthenticationHandler {
private static final List<MessageDescriptor> warningList = new ArrayList<>();
public CustomAuthenticationHandler(String name, ServicesManager servicesManager, PrincipalFactory principalFactory, Integer order) {
super(name, servicesManager, principalFactory, order);
}
@Override
protected AuthenticationHandlerExecutionResult authenticateUsernamePasswordInternal(UsernamePasswordCredential credential, String originalPassword) throws GeneralSecurityException, PreventedException {
// todo 定义自己的验证方法
String username = credential.getUsername();
String password = credential.getPassword();
if(username.equals("wenyoulong")){
return createHandlerResult(credential,
principalFactory.createPrincipal(username), warningList);
}
throw new FailedLoginException("Sorry, you are a failure!");
}
}
定义好自定义的认证处理器后,要把这个认证处理器注册到cas,配置如下
package org.apereo.cas.custom.config;
import org.apereo.cas.authentication.AuthenticationEventExecutionPlanConfigurer;
import org.apereo.cas.authentication.AuthenticationHandler;
import org.apereo.cas.authentication.principal.PrincipalFactory;
import org.apereo.cas.configuration.CasConfigurationProperties;
import org.apereo.cas.custom.handler.CustomAuthenticationHandler;
import org.apereo.cas.services.ServicesManager;
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.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableConfigurationProperties(CasConfigurationProperties.class)
public class CustomCasConfiguration{
@Autowired
private ServicesManager servicesManager;
@Autowired
private PrincipalFactory principalFactory;
@Bean
public AuthenticationHandler myAuthenticationHandler() {
return new CustomAuthenticationHandler(CustomAuthenticationHandler.class.getName(),servicesManager,principalFactory,1);
}
@Bean
public AuthenticationEventExecutionPlanConfigurer myPlan(
@Qualifier("myAuthenticationHandler")
final AuthenticationHandler myAuthenticationHandler) {
return plan -> {
plan.registerAuthenticationHandler(myAuthenticationHandler);
};
}
}
官方其实是帮我们集成了根据数据源查询用户的操作(参考CAS数据库查询账号),但是封装的太死了,我们要添加功能会比较困难,因此不使用官方的操作,改用自己的数据源配置
在pom文件中引入自己的数据源依赖和驱动,这里我使用c3p0
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>${c3p0.version}</version>
</dependency>
建立配置类
package org.apereo.cas.custom.config;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import javax.sql.DataSource;
import java.beans.PropertyVetoException;
@Configuration
public class DatasourceConfiguration {
@Value("${spring.datasource.driverClassName}")
private String driver;
@Value("${spring.datasource.url}")
private String url;
@Value("${spring.datasource.username}")
private String username;
@Value("${spring.datasource.password}")
private String password;
@Bean(name = "c3p0Datasource")
public DataSource createDataSource() throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setDriverClass(driver);
dataSource.setJdbcUrl(url);
dataSource.setUser(username);
dataSource.setPassword(password);
dataSource.setAutoCommitOnClose(false);
dataSource.setInitialPoolSize(10);
dataSource.setMinPoolSize(10);
dataSource.setMaxPoolSize(100);
return dataSource;
}
@Bean(name = "c3p0JdbcTemplate")
public JdbcTemplate createJdbcTemplate(@Autowired @Qualifier("c3p0Datasource") DataSource dataSource){
return new JdbcTemplate(dataSource);
}
}
在application.properties中新增数据源配置
spring.datasource.url=jdbc:mysql://192.168.56.5:3306/cas-user?useUnicode=true&useSSL=false&characterEncoding=utf-8&serverTimezone=GMT%2B8
spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=root
修改之前的配置类,将JDBCTemplate作为参数传递到认证服务中
package org.apereo.cas.custom.config;
import org.apereo.cas.authentication.AuthenticationEventExecutionPlanConfigurer;
import org.apereo.cas.authentication.AuthenticationHandler;
import org.apereo.cas.authentication.principal.PrincipalFactory;
import org.apereo.cas.configuration.CasConfigurationProperties;
import org.apereo.cas.custom.handler.CustomAuthenticationHandler;
import org.apereo.cas.custom.util.C3p0Util;
import org.apereo.cas.services.ServicesManager;
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.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import javax.sql.DataSource;
@Configuration
@EnableConfigurationProperties(CasConfigurationProperties.class)
public class CustomCasConfiguration{
@Autowired
private ServicesManager servicesManager;
@Autowired
private PrincipalFactory principalFactory;
@Autowired
@Qualifier("c3p0JdbcTemplate")
private JdbcTemplate jdbcTemplate;
@Bean
public AuthenticationHandler myAuthenticationHandler() {
return new CustomAuthenticationHandler(CustomAuthenticationHandler.class.getName(),servicesManager,principalFactory,1,jdbcTemplate);
}
@Bean
public AuthenticationEventExecutionPlanConfigurer myPlan(
@Qualifier("myAuthenticationHandler")
final AuthenticationHandler myAuthenticationHandler) {
return plan -> {
plan.registerAuthenticationHandler(myAuthenticationHandler);
};
}
}
package org.apereo.cas.custom.handler;
import org.apereo.cas.authentication.AuthenticationHandlerExecutionResult;
import org.apereo.cas.authentication.MessageDescriptor;
import org.apereo.cas.authentication.PreventedException;
import org.apereo.cas.authentication.UsernamePasswordCredential;
import org.apereo.cas.authentication.handler.support.AbstractUsernamePasswordAuthenticationHandler;
import org.apereo.cas.authentication.principal.PrincipalFactory;
import org.apereo.cas.custom.entity.CasUser;
import org.apereo.cas.custom.util.AESUtil;
import org.apereo.cas.custom.util.PasswordUtil;
import org.apereo.cas.services.ServicesManager;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import javax.security.auth.login.FailedLoginException;
import java.security.GeneralSecurityException;
import java.util.ArrayList;
import java.util.List;
public class CustomAuthenticationHandler extends AbstractUsernamePasswordAuthenticationHandler {
private static final List<MessageDescriptor> warningList = new ArrayList<>();
private final JdbcTemplate jdbcTemplate;
public CustomAuthenticationHandler(String name, ServicesManager servicesManager, PrincipalFactory principalFactory, Integer order,JdbcTemplate jdbcTemplate) {
super(name, servicesManager, principalFactory, order);
this.jdbcTemplate = jdbcTemplate;
}
@Override
protected AuthenticationHandlerExecutionResult authenticateUsernamePasswordInternal(UsernamePasswordCredential credential, String originalPassword) throws GeneralSecurityException, PreventedException {
String username = credential.getUsername();
String password = AESUtil.aesDecrypt(credential.getPassword());
String sql = "SELECT * FROM cas_user WHERE username = ?";
long startQueryTimes = System.currentTimeMillis();
CasUser info = (CasUser) jdbcTemplate.queryForObject(sql, new Object[]{username}, new BeanPropertyRowMapper(CasUser.class));
long endQueryTimes = System.currentTimeMillis();
System.out.println("数据库查询用时"+(endQueryTimes-startQueryTimes));
String truePwd = info.getPassword();
long startEncryptTimes = System.currentTimeMillis();
// 加密解密工具类,根据自己的需求,换成自己的加密解密方法
String encryptPwd = PasswordUtil.encrypt(username, password, info.getSalt());
long endEncryptTimes = System.currentTimeMillis();
System.out.println("加密时间"+(endEncryptTimes-startEncryptTimes));
if(encryptPwd.equals(truePwd)){
return createHandlerResult(credential,
principalFactory.createPrincipal(username), warningList);
}
throw new FailedLoginException("密码不正确!");
}
}
CasUser实体如下,根据自己的需求增删字段
package org.apereo.cas.custom.entity;
import lombok.Data;
import org.joda.time.DateTime;
import java.time.LocalDateTime;
@Data
public class CasUser {
private String id;
private String username;
private String password;
private String salt;
private String phoneNumber;
private String source_sys;
private LocalDateTime create_time;
private LocalDateTime update_tIme;
}