cas基础--自定义认证策略

Updated on with 0 views and 0 comments

一、自定义配置

1.1 配置类

cas官方给出了自定义配置的方法,详情可以参考cas配置扩展

package org.apereo.cas.custom.config;

@Configuration
@EnableConfigurationProperties(CasConfigurationProperties.class)
public class CustomCasConfiguration {
    // todo 将自己的配置类注册到容器
}

1.2 自动加载配置

这里需要先引入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文件即可

image.png

文件内容为

org.springframework.boot.autoconfigure.EnableAutoConfiguration=org.apereo.cas.custom.config.CustomCasConfiguration

1.3 官方实现了的认证策略

官方帮我们默认实现了很多认证方法可以参考自定义认证方法,根据自己的需要选择即可,官方文档中已经明确告诉我们各个认证方法的引入及配置方式了,就不再赘述

image.png

1.4 自定义认证策略

如果官方提供的方法都不能满足我们的需求,那么就可以自定义认证方法,可以参考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);
        };
    }
}

1.5 集成数据源

官方其实是帮我们集成了根据数据源查询用户的操作(参考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;
}


标题:cas基础--自定义认证策略
作者:wenyl
地址:http://www.wenyoulong.com/articles/2023/09/06/1693985182319.html