H__D  

原理

  在 CAS 5.3.2 中,登录成功后返回用户的多个属性内容是通过 Principal 对象实现的。Principal 包含了用户的基本信息(如用户名)以及额外的属性(如邮箱、电话、角色等)。

  具体逻辑其实还是在 AuthenticationHandler 处理的,AuthenticationHandler原理参考(【CAS】CAS 自定义登录验证(四) - H__D - 博客园

数据库验证用户多属性返回

  AI回答如下:

1. 配置数据库认证

首先,配置 CAS 使用数据库进行用户认证。CAS 提供了 QueryDatabaseAuthenticationHandler 用于从数据库中验证用户。

修改 application.properties 或 cas.properties

properties
复制
# 启用数据库认证
cas.authn.jdbc.query[0].sql=SELECT * FROM users WHERE username=?
cas.authn.jdbc.query[0].url=jdbc:mysql://localhost:3306/cas
cas.authn.jdbc.query[0].user=root
cas.authn.jdbc.query[0].password=password
cas.authn.jdbc.query[0].driverClass=com.mysql.cj.jdbc.Driver
cas.authn.jdbc.query[0].fieldPassword=password
cas.authn.jdbc.query[0].fieldExpired=expired
cas.authn.jdbc.query[0].fieldDisabled=disabled
  • sql:查询用户的 SQL 语句。

  • url:数据库连接 URL。

  • user:数据库用户名。

  • password:数据库密码。

  • driverClass:数据库驱动类。

  • fieldPassword:密码字段。

  • fieldExpired:账户是否过期的字段。

  • fieldDisabled:账户是否禁用的字段。


2. 返回用户多属性

在数据库查询中,除了验证用户名和密码,还可以查询用户的多个属性(如邮箱、电话、角色等),并将这些属性返回给 CAS。

修改 SQL 查询

确保 SQL 查询返回用户的多个属性。例如:

sql
复制
SELECT username, password, email, phone, roles FROM users WHERE username=?

配置属性映射

在 application.properties 或 cas.properties 中,配置数据库字段到 CAS 属性的映射:

properties
复制
cas.authn.jdbc.query[0].principalAttributeList=email,phone,roles
cas.authn.jdbc.query[0].attributeMapping.email=email
cas.authn.jdbc.query[0].attributeMapping.phone=phone
cas.authn.jdbc.query[0].attributeMapping.roles=roles
  • principalAttributeList:指定要返回的属性名称。

  • attributeMapping:将数据库字段映射到 CAS 属性。


3. 自定义 Principal 属性

如果默认的 QueryDatabaseAuthenticationHandler 无法满足需求,您可以实现自定义的 AuthenticationHandler,从数据库中查询用户属性并返回。

自定义 AuthenticationHandler 示例

java
复制
package com.example.cas.auth;

import org.apereo.cas.authentication.AuthenticationHandlerExecutionResult;
import org.apereo.cas.authentication.Credential;
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 org.springframework.jdbc.core.JdbcTemplate;

import javax.security.auth.login.FailedLoginException;
import javax.sql.DataSource;
import java.security.GeneralSecurityException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class DatabaseAuthenticationHandler extends AbstractUsernamePasswordAuthenticationHandler {

    private final JdbcTemplate jdbcTemplate;

    public DatabaseAuthenticationHandler(String name, ServicesManager servicesManager, PrincipalFactory principalFactory, Integer order, DataSource dataSource) {
        super(name, servicesManager, principalFactory, order);
        this.jdbcTemplate = new JdbcTemplate(dataSource);
    }

    @Override
    protected AuthenticationHandlerExecutionResult authenticateUsernamePasswordInternal(UsernamePasswordCredential credential, String originalPassword)
            throws GeneralSecurityException, PreventedException {

        String username = credential.getUsername();
        String password = credential.getPassword();

        // 查询用户信息
        String sql = "SELECT username, password, email, phone, roles FROM users WHERE username=?";
        List<Map<String, Object>> result = jdbcTemplate.queryForList(sql, username);

        if (result.isEmpty()) {
            throw new FailedLoginException("User not found: " + username);
        }

        Map<String, Object> user = result.get(0);
        String dbPassword = (String) user.get("password");

        // 验证密码
        if (!password.equals(dbPassword)) {
            throw new FailedLoginException("Invalid password for user: " + username);
        }

        // 定义用户属性
        Map<String, Object> attributes = new HashMap<>();
        attributes.put("email", user.get("email"));
        attributes.put("phone", user.get("phone"));
        attributes.put("roles", user.get("roles"));

        // 创建 Principal 对象,包含用户名和属性
        return createHandlerResult(credential, this.principalFactory.createPrincipal(username, attributes));
    }

    @Override
    public boolean supports(Credential credential) {
        return credential instanceof UsernamePasswordCredential;
    }
}

4. 注册自定义 AuthenticationHandler

通过 AuthenticationEventExecutionPlanConfigurer 接口将自定义的 DatabaseAuthenticationHandler 注册到 CAS 的认证流程中。

注册自定义处理器

java
复制
package com.example.cas.config;

import com.example.cas.auth.DatabaseAuthenticationHandler;
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;

import javax.sql.DataSource;

@Configuration("databaseAuthenticationConfiguration")
public class DatabaseAuthenticationConfiguration implements AuthenticationEventExecutionPlanConfigurer {

    @Autowired
    @Qualifier("servicesManager")
    private ServicesManager servicesManager;

    @Autowired
    private DataSource dataSource;

    @Bean
    public AuthenticationHandler databaseAuthenticationHandler() {
        return new DatabaseAuthenticationHandler(
            DatabaseAuthenticationHandler.class.getSimpleName(), // 处理器名称
            servicesManager, // ServicesManager
            new DefaultPrincipalFactory(), // PrincipalFactory
            1, // 处理器顺序
            dataSource // 数据源
        );
    }

    @Override
    public void configureAuthenticationExecutionPlan(AuthenticationEventExecutionPlan plan) {
        // 注册自定义的认证处理器
        plan.registerAuthenticationHandler(databaseAuthenticationHandler());
    }
}

5. 配置 CAS 返回属性

在 application.properties 或 cas.properties 中,启用属性释放功能:

properties
复制
# 启用属性释放
cas.authn.attributeRepository.defaultAttributesToRelease=email,phone,roles

6. 测试登录并获取属性

  1. 启动 CAS 服务

    • 使用以下命令打包并启动 CAS:

      bash
      复制
      ./gradlew clean build
      ./gradlew run
  2. 访问 CAS 登录页面

    • 打开浏览器,访问 http://localhost:8080/cas/login

  3. 登录并查看属性

    • 使用数据库中的用户名和密码登录。

    • 登录成功后,CAS 会返回包含用户属性的票据(如 TGT 或 ST)。

    • 在服务端,可以通过 CAS 客户端库解析票据,获取用户属性。


7. 总结

通过以上步骤,您可以在 CAS 登录成功后返回数据库用户的多个属性内容。关键点包括:

  1. 配置数据库认证。

  2. 在 SQL 查询中返回用户属性。

  3. 配置属性映射和释放。

  4. 实现自定义的 AuthenticationHandler(可选)。

  5. 在客户端解析票据,获取用户属性。

这种方法适用于 CAS 5.3.2 及更高版本,能够灵活地从数据库中获取并返回用户属性。

测试验证

  本例测试的是数据库查询用户,并返回属性,具体逻辑在源码的 QueryDatabaseAuthenticationHandler 类中

1、在application.properties配置

复制代码
# 查询配置
cas.authn.attributeRepository.jdbc[0].dialect=org.hibernate.dialect.MySQLDialect
cas.authn.attributeRepository.jdbc[0].driverClass=com.mysql.cj.jdbc.Driver
cas.authn.attributeRepository.jdbc[0].url=jdbc:mysql://127.0.0.1:3306/cas?characterEncoding=UTF-8&nullCatalogMeansCurrent=true&useSSL=false&rewriteBatchedStatements=true
cas.authn.attributeRepository.jdbc[0].user=root
cas.authn.attributeRepository.jdbc[0].password=123456

# 查询SQL
cas.authn.attributeRepository.jdbc[0].sql=select * from user where {0}
# 以下属性为查询sql时,当为多个时逗号分隔,如填写username、email,sql会变成 select * from user where username=${?} {and/or} email=${?}
cas.authn.attributeRepository.jdbc[0].username=username
cas.authn.attributeRepository.jdbc[0].singleRow=true
cas.authn.attributeRepository.jdbc[0].order=0
cas.authn.attributeRepository.jdbc[0].requireAllAttributes=true
# cas.authn.attributeRepository.jdbc[0].caseCanonicalization=NONE|LOWER|UPPER
# cas.authn.attributeRepository.jdbc[0].queryType=OR|AND

# 单行属性
cas.authn.attributeRepository.jdbc[0].attributes.id=id
cas.authn.attributeRepository.jdbc[0].attributes.username=username
cas.authn.attributeRepository.jdbc[0].attributes.first_name=first_name
cas.authn.attributeRepository.jdbc[0].attributes.last_name=last_name
复制代码

 

2、启动CAS服务,登录

  登录成功,

  

  点击查询属性,可以看到 id、first_name、last_name、username 均已返回

  

 

 

   

 

posted on   H__D  阅读(31)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Blazor Hybrid适配到HarmonyOS系统
· Obsidian + DeepSeek:免费 AI 助力你的知识管理,让你的笔记飞起来!
· 解决跨域问题的这6种方案,真香!
· 一套基于 Material Design 规范实现的 Blazor 和 Razor 通用组件库
· 数据并发安全校验处理工具类
历史上的今天:
2024-01-19 【Mybatis-Plus】Mybatis-Plus多数据源(三)
2024-01-19 【Mybatis-Plus】Mybatis-Plus代码生成器(二)
2019-01-19 【NIFI】 Apache NiFI 使用技巧
 
点击右上角即可分享
微信分享提示