• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
Y-wee
博客园    首页    新随笔    联系   管理     

CAS 5.3版本自定义JDBC认证策略

CAS 5.3版本自定义JDBC认证策略

​ CAS 官方文档是介绍基于配置实现 jdbc 认证的,不过有时候认证逻辑比较复杂,比如:数据库存储的密码是通过动态盐加密的,此时我们需要通过自定义认证策略的方式实现认证

​ pom 文件引入依赖

<!--开启cas server的rest支持-->
<dependency>
    <groupId>org.apereo.cas</groupId>
    <artifactId>cas-server-support-rest</artifactId>
    <version>${cas.version}</version>
</dependency>

<!-- 数据库 -->
<dependency>
    <groupId>org.apereo.cas</groupId>
    <artifactId>cas-server-support-jdbc</artifactId>
    <version>${cas.version}</version>
</dependency>
<dependency>
    <groupId>org.apereo.cas</groupId>
    <artifactId>cas-server-support-jdbc-drivers</artifactId>
    <version>${cas.version}</version>
</dependency>

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.27</version>
</dependency>

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.24</version>
</dependency>

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-dbcp2</artifactId>
    <version>2.3.0</version>
</dependency>

<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-core</artifactId>
    <version>1.4.0</version>
</dependency>

<!--自定义认证-->
<dependency>
    <groupId>org.apereo.cas</groupId>
    <artifactId>cas-server-core-authentication-api</artifactId>
    <version>${cas.version}</version>
</dependency>
<dependency>
    <groupId>org.apereo.cas</groupId>
    <artifactId>cas-server-core-configuration-api</artifactId>
    <version>${cas.version}</version>
</dependency>
<dependency>
    <groupId>org.apereo.cas</groupId>
    <artifactId>cas-server-support-generic</artifactId>
    <version>${cas.version}</version>
</dependency>

​ 注意依赖添加位置(在标记处下面添加新的依赖):

​ 继承 AbstractPreAndPostProcessingAuthenticationHandler 抽象类,自定义认证逻辑:

package com.povison.handler;

import com.povison.domain.entity.SysUser;
import com.povison.util.PasswordUtil;
import org.apache.shiro.authc.AccountException;
import org.apereo.cas.authentication.AuthenticationHandlerExecutionResult;
import org.apereo.cas.authentication.Credential;
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.AbstractPreAndPostProcessingAuthenticationHandler;
import org.apereo.cas.authentication.principal.PrincipalFactory;
import org.apereo.cas.services.ServicesManager;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.util.ObjectUtils;

import javax.security.auth.login.FailedLoginException;
import java.security.GeneralSecurityException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * 自定义认证处理器
 *
 * @author Y-wee
 */
public class CustomAuthenticationHandler extends AbstractPreAndPostProcessingAuthenticationHandler {

    public CustomAuthenticationHandler(String name, ServicesManager servicesManager, PrincipalFactory principalFactory, Integer order) {
        super(name, servicesManager, principalFactory, order);
    }

    /**
     * 执行身份验证的详细信息并在成功时返回身份验证处理程序结果
     *
     * @param credential
     * @return
     * @throws GeneralSecurityException
     * @throws PreventedException
     */
    @Override
    protected AuthenticationHandlerExecutionResult doAuthentication(Credential credential) throws GeneralSecurityException, PreventedException {
        UsernamePasswordCredential usernamePasswordCredential = (UsernamePasswordCredential) credential;
        String username = usernamePasswordCredential.getUsername();
        String password = usernamePasswordCredential.getPassword();

        /*
        构建数据库驱动连接池
         */
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/test?characterEncoding=UTF-8&useUnicode=true&useSSL=false&tinyInt1isBit=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai");
        dataSource.setUsername("root");
        dataSource.setPassword("123456");

        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        jdbcTemplate.setDataSource(dataSource);

        String sql = "SELECT salt,password FROM sys_user WHERE status=1 and username = ?";
        SysUser sysUser = (SysUser) jdbcTemplate.queryForObject(sql, new Object[]{username}, new BeanPropertyRowMapper(SysUser.class));

        if (ObjectUtils.isEmpty(sysUser)) {
            throw new AccountException("Sorry, username not found!");
        }
		/*
		 * 将密码加密后与数据库查询出来的密码比较,验证密码是否正确
		 */
        String encryptPassword=PasswordUtil.encrypt(username, password, sysUser.getSalt());
        if (!sysUser.getPassword().equals(encryptPassword)) {
            throw new FailedLoginException("Sorry, password not correct!");
        } else {
            final List<MessageDescriptor> list = new ArrayList<>();
            return createHandlerResult(usernamePasswordCredential,
                    this.principalFactory.createPrincipal(username, Collections.emptyMap()), list);
        }
    }

    /**
     * Determines whether the handler has the capability to authenticate the given credential. In practical terms,
     * the {@link #authenticate(Credential)} method MUST be capable of processing a given credential if
     * {@code supports} returns true on the same credential.
     *
     * @param credential The credential to check.
     * @return True if the handler supports the Credential, false otherwise.
     */
    @Override
    public boolean supports(Credential credential) {
        return credential instanceof UsernamePasswordCredential;
    }
}

​ 新增一个配置类,实现 AuthenticationEventExecutionPlanConfigurer 接口:

package com.povison.config;

import com.povison.handler.CustomAuthenticationHandler;
import org.apereo.cas.authentication.AuthenticationEventExecutionPlan;
import org.apereo.cas.authentication.AuthenticationEventExecutionPlanConfigurer;
import org.apereo.cas.authentication.AuthenticationHandler;
import org.apereo.cas.authentication.PrePostAuthenticationHandler;
import org.apereo.cas.authentication.principal.DefaultPrincipalFactory;
import org.apereo.cas.configuration.CasConfigurationProperties;
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;

/**
 * 自定义用户认证的实体类注册配置类
 *
 * @author Y-wee
 */
@Configuration("CustomAuthConfig")
@EnableConfigurationProperties(CasConfigurationProperties.class)
public class CustomAuthConfig implements AuthenticationEventExecutionPlanConfigurer {
    @Autowired
    @Qualifier("servicesManager")
    private ServicesManager servicesManager;

    /**
     * 配置 PrePostAuthenticationHandler Bean
     *
     * @return
     */
    @Bean
    public PrePostAuthenticationHandler getAuthenticationHandler() {
        return new CustomAuthenticationHandler(CustomAuthenticationHandler.class.getName(),
                servicesManager, new DefaultPrincipalFactory(), 1);
    }

    /**
     * configure the plan.
     *
     * @param plan
     */
    @Override
    public void configureAuthenticationExecutionPlan(AuthenticationEventExecutionPlan plan) {
        plan.registerAuthenticationHandler(getAuthenticationHandler());
    }
}

​ 在 resource 资源文件夹下新建 META-INF/spring.factories 文件,添加自动配置类:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.povison.config.CustomAuthConfig

​ 将注释 application.properties 中配置的默认账号信息注释

#cas.authn.accept.users=casuser::Mellon

​ 重启服务,即可通过数据库存储的账号信息登录了

​ 参考文档:https://cloud.tencent.com/developer/article/1623476

记得快乐
posted @ 2023-03-02 16:23  Y-wee  阅读(361)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3