You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何修改CAS 5.x,使其通过REST API完成用户身份校验

嘿,我太懂CAS 5.x和3.x的配置差异有多让人头疼了!尤其是REST API对接自定义用户服务这块,逻辑完全变了。我来一步步给你捋清楚怎么配置,让CAS调用你的用户服务接口完成用户名密码校验。

CAS 5.x 集成自定义REST用户认证服务指南

一、先搞懂CAS 5.x的认证逻辑变化

CAS 5.x换成了Spring Boot架构,把认证流程拆成了一堆可插拔的组件,不像3.x那样靠XML硬写配置。要对接你的自定义REST用户服务,核心是实现AuthenticationHandler接口(或者用CAS现成的REST组件,但自定义处理器会更灵活适配你的接口)。

二、步骤1:添加必要依赖

先在CAS项目的pom.xml里加好依赖——要调用REST接口,Spring的RestTemplate是基础,另外如果想用CAS官方的REST认证基础模块,也可以一并加上:

<dependency>
    <groupId>org.apereo.cas</groupId>
    <artifactId>cas-server-support-rest-authentication</artifactId>
    <version>${cas.version}</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>${spring.version}</version>
</dependency>

三、步骤2:实现自定义认证处理器

这是核心环节,我们写一个类继承AbstractUsernamePasswordAuthenticationHandler,重写校验方法,在里面调用你的用户服务接口:

package com.yourorg.cas.extensions;

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.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

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

public class RestUserAuthenticationHandler extends AbstractUsernamePasswordAuthenticationHandler {

    private final RestTemplate restTemplate;
    private final String userServiceUrl;

    // 构造方法,注入必要的CAS组件和自定义配置
    public RestUserAuthenticationHandler(String name, ServicesManager servicesManager, PrincipalFactory principalFactory,
                                         Integer order, RestTemplate restTemplate, String userServiceUrl) {
        super(name, servicesManager, principalFactory, order);
        this.restTemplate = restTemplate;
        this.userServiceUrl = userServiceUrl;
    }

    @Override
    protected AuthenticationHandlerExecutionResult authenticateUsernamePasswordInternal(UsernamePasswordCredential credential, String originalPassword) throws GeneralSecurityException, PreventedException {
        String username = credential.getUsername();
        String password = credential.getPassword();

        // 按你的用户服务接口要求构造请求参数
        Map<String, String> requestBody = new HashMap<>();
        requestBody.put("username", username);
        requestBody.put("password", password);

        HttpHeaders headers = new HttpHeaders();
        headers.set("Content-Type", "application/json");
        HttpEntity<Map<String, String>> requestEntity = new HttpEntity<>(requestBody, headers);

        try {
            // 调用你的用户服务校验接口
            ResponseEntity<Map> response = restTemplate.exchange(userServiceUrl, HttpMethod.POST, requestEntity, Map.class);
            
            if (response.getStatusCode().is2xxSuccessful()) {
                Map<String, Object> userInfo = response.getBody();
                // 假设接口返回格式是{"success": true, "userId": "123", "email": "user@example.com"}
                boolean authSuccess = (Boolean) userInfo.get("success");
                if (authSuccess) {
                    // 构造CAS认可的用户身份信息,把接口返回的用户数据也带进去
                    return createHandlerResult(credential, this.principalFactory.createPrincipal(username, userInfo), null);
                } else {
                    throw new FailedLoginException("用户名或密码错误");
                }
            } else {
                throw new PreventedException("用户服务接口调用失败,状态码:" + response.getStatusCodeValue());
            }
        } catch (Exception e) {
            throw new PreventedException("调用用户服务时发生异常", e);
        }
    }
}

四、步骤3:注册自定义处理器到CAS

CAS 5.x用Spring Java Config管理组件,我们写一个配置类,把刚才的处理器注册到CAS的认证流程里:

package com.yourorg.cas.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.services.ServicesManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration("restUserAuthConfig")
@EnableConfigurationProperties(CasConfigurationProperties.class)
public class RestUserAuthenticationConfiguration implements AuthenticationEventExecutionPlanConfigurer {

    @Autowired
    private ServicesManager servicesManager;

    @Autowired
    private PrincipalFactory principalFactory;

    @Autowired
    private CasConfigurationProperties casProperties;

    // 初始化RestTemplate实例
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

    // 实例化自定义认证处理器
    @Bean
    public AuthenticationHandler restUserAuthenticationHandler() {
        // 从CAS配置文件里读取用户服务地址,方便后续修改
        String userServiceUrl = casProperties.getAuthn().getRest().getUrl();
        RestUserAuthenticationHandler handler = new RestUserAuthenticationHandler(
                "RestUserAuthenticationHandler",
                servicesManager,
                principalFactory,
                10, // 执行顺序,数字越小越先执行,可根据你的需求调整
                restTemplate(),
                userServiceUrl
        );
        return handler;
    }

    // 把处理器注册到CAS的认证执行计划里
    @Override
    public void configureAuthenticationExecutionPlan(AuthenticationEventExecutionPlan plan) {
        plan.registerAuthenticationHandler(restUserAuthenticationHandler());
    }
}

五、步骤4:配置CAS参数

在CAS的application.properties(或application.yml)里添加自定义配置,比如你的用户服务接口地址:

# 自定义REST用户服务配置
cas.authn.rest.url=http://your-user-service/api/auth/check
# 如果你的用户服务需要Basic Auth认证,可以加下面两行
# cas.authn.rest.basic-auth.username=admin
# cas.authn.rest.basic-auth.password=your-secret

另外,要让CAS扫描到我们的配置类,需要在src/main/resources/META-INF/spring.factories里添加:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.yourorg.cas.config.RestUserAuthenticationConfiguration

六、测试验证

部署CAS后,你可以用curl调用CAS的REST认证接口测试:

curl -X POST -H "Content-Type: application/json" -d '{"username":"testuser","password":"testpass"}' https://your-cas-server/cas/v1/tickets

如果认证成功,会返回一个TGT(Ticket Granting Ticket),说明你的自定义用户服务已经生效了。

一些注意事项

  • 执行顺序很重要:如果CAS还有其他认证处理器(比如数据库认证),要调整order参数,确保自定义处理器能被优先执行;
  • 异常处理要完善:上面的代码做了基础的异常捕获,你可以根据实际情况扩展超时、连接失败等场景的处理;
  • 接口适配:如果你的用户服务接口有特殊的请求头、认证方式(比如OAuth2 Token),可以在RestTemplate里添加对应的拦截器或配置。

内容的提问来源于stack exchange,提问作者Felix Xie

火山引擎 最新活动