完整实现指南)
后端认证鉴权单点登录【免费下载链接】casApereo CAS - Identity Single Sign On for all earthlings and beyond.项目地址https://gitcode.com/gh_mirrors/ca/cas点击查看免费下载导读本文聚焦 Apereo CAS 无密码Passwordless认证体系中用户账户存储这一核心扩展点讲解如何通过实现PasswordlessUserAccountStore接口、注册自定义 Spring Bean 来替换或扩展现有账户数据源。阅读本文后你将掌握PasswordlessUserAccountStore接口的定义与职责、CAS 默认提供的多种账户存储实现及加载机制、账户模型PasswordlessUserAccount的全部字段语义以及如何在 CAS Overlay 中以源码级方式编写并注册自定义存储让无密码登录直接对接你自有目录中的用户数据。自定义用户账户存储核心思路在 CAS 的 Passwordless 认证流程中当用户提交用户名后CAS 需要一个账户查找环节来决定该用户是否可以发起无密码认证以及应当向哪个联系方式邮箱/手机号发送一次性令牌。这一查找行为被抽象为PasswordlessUserAccountStore接口。官方文档 Passwordless-Authentication-Storage-Custom.md 明确指出你可以定义自己的用户账户存储只需实现PasswordlessUserAccountStore接口并以如下 Bean 定义将其注册到 CAS 运行时Bean public PasswordlessUserAccountStore passwordlessUserAccountStore() { ... }这里有两个关键点需要留意Bean 名称必须是passwordlessUserAccountStore。该名称正是接口中声明的常量BEAN_NAME见 PasswordlessUserAccountStore.javaCAS 的自动配置在装配默认存储时使用了ConditionalOnMissingBean(name PasswordlessUserAccountStore.BEAN_NAME)进行守卫见 CasPasswordlessAuthenticationAutoConfiguration.java。只要你的自定义 Bean 以同名注册CAS 就会跳过内部默认组装逻辑直接使用你的实现。注册位置自定义配置类需要能被 CAS 的AutoConfiguration机制扫描到。具体注册方法参见 Configuration-Management-Extensions.md将配置类全限定名写入src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件即可。接口定义与契约PasswordlessUserAccountStore位于support/cas-server-support-passwordless-api模块是一个标注了FunctionalInterface的接口源码见 PasswordlessUserAccountStore.javaFunctionalInterface public interface PasswordlessUserAccountStore { String BEAN_NAME passwordlessUserAccountStore; Optional? extends PasswordlessUserAccount findUser(PasswordlessAuthenticationRequest request) throws Throwable; default void reload() { } }接口契约包含两部分findUser(PasswordlessAuthenticationRequest request)唯一必须实现的方法。入参是封装了用户名的PasswordlessAuthenticationRequest返回Optional? extends PasswordlessUserAccount。返回Optional.empty()表示未找到该用户CAS 将拒绝发起无密码认证返回账户对象则表示命中后续流程将据此发送令牌。reload()默认空实现用于支持账户数据的运行时刷新。例如基于 JSON 文件的存储实现会通过它重读文件内容见下文。如果你的自定义存储有缓存或外部数据源变更场景建议重写该方法。请求对象PasswordlessAuthenticationRequestfindUser的入参类型为 PasswordlessAuthenticationRequest.java自 7.0.0 版本引入字段如下字段类型说明usernameString用户在登录页面提交的用户名必填providedUsernameString额外提供的用户名信息可为空propertiesMapString, String附加请求属性集合可用于传递上下文信息账户模型PasswordlessUserAccount返回的账户对象类型为 PasswordlessUserAccount.java其字段决定了无密码认证的后续行为字段类型默认值语义usernameString-用户名emailString-邮箱令牌将发送至此需与phone至少提供一个phoneJSON 字段名phoneNumberString-手机号令牌发送的备选渠道nameString-显示名称attributesMapString, ListObject空LinkedHashMap用户属性将并入最终认证主体PrincipalmultifactorAuthenticationEligibleTriStateBooleanUNDEFINED是否允许/要求多因素认证三态布尔可显式 true/false 或保持未定义delegatedAuthenticationEligibleTriStateBooleanUNDEFINED是否允许委托认证如通过外部 IdP 登录allowedDelegatedClientsListString空列表允许使用的委托客户端白名单requestPasswordbooleanfalse是否要求用户额外输入密码allowSelectionMenubooleanfalse是否允许显示账户选择菜单sourceString-账户来源标识其中hasContactInformation()方法用于校验账户是否具备联系方式email或phone至少一个非空这是 CAS 判断能否发送令牌的依据。该模型使用 Jackson 序列化JsonTypeInfo(use JsonTypeInfo.Id.CLASS)保留类型信息因此从 REST 或 JSON 数据源反序列化时返回结构需要与该字段集合兼容。CAS 内置的账户存储实现在动手编写自定义实现之前先了解 CAS 自带的几种PasswordlessUserAccountStore实现它们既可以直接使用也可以作为自定义实现的参考模板。全部位于support/cas-server-support-passwordless-api/src/main/java/org/apereo/cas/impl/account/目录实现类数据来源触发配置SimplePasswordlessUserAccountStore配置文件中的键值对cas.authn.passwordless.accounts.simple.*JsonPasswordlessUserAccountStoreJSON 文件cas.authn.passwordless.accounts.json.locationGroovyPasswordlessUserAccountStoreGroovy 脚本cas.authn.passwordless.accounts.groovy.locationRestfulPasswordlessUserAccountStoreREST 接口cas.authn.passwordless.accounts.rest.url组合器ChainingPasswordlessAccountStore需要注意CAS 默认装配的passwordlessUserAccountStore并非上述某一个实现而是一个组合存储ChainingPasswordlessAccountStore.java自动配置会收集容器中所有PasswordlessUserAccountStore类型的 Bean含内置的 JSON/Groovy/REST/Simple 存储与用户自定义存储按AnnotationAwareOrderComparator排序后包装为链式查找。findUser依次询问每个子存储返回第一个命中结果见 CasPasswordlessAuthenticationAutoConfiguration.java。这意味着如果你自定义的存储 Bean使用了其他名称而非passwordlessUserAccountStore它会被自动纳入默认链式存储中作为补充数据源如果你自定义的 Bean使用标准名称passwordlessUserAccountStore则完全替换掉默认链式存储此时你需要自行处理多数据源逻辑。SimplePasswordlessUserAccountStore配置驱动的极简实现该实现内部维护MapString, PasswordlessUserAccount accountsfindUser时使用正则匹配以配置中的 key 作为正则表达式对请求用户名做RegexUtils.find(key, username)匹配命中即返回对应账户见 SimplePasswordlessUserAccountStore.java。由于 key 被当作正则处理你甚至可以用user.*之类的模式批量匹配用户。其对应的测试用例 SimplePasswordlessUserAccountStoreTests.java 展示了最简配置形态cas.authn.passwordless.accounts.simple.casuser1234567890 cas.authn.passwordless.tokens.crypto.enabledfalse配置值会被自动识别为邮箱或手机号EmailValidator判定为合法邮箱则设置email否则设置phone见 CasPasswordlessAuthenticationAutoConfiguration.java。测试中casuser查询返回账户、other查询返回空验证了查找与 miss 两条路径。JsonPasswordlessUserAccountStore文件热加载该实现继承SimplePasswordlessUserAccountStore从 JSON 文件读取账户 Map并通过FileWatcherService监控文件变化一旦文件被修改就触发reload()重新加载见 JsonPasswordlessUserAccountStore.java。JSON 文件结构与账户模型对应例如{ casuser: { username: casuser, email: casuserexample.org, phoneNumber: 1234567890, name: CAS User, attributes: { memberOf: [staff] }, requestPassword: false, allowSelectionMenu: false } }GroovyPasswordlessUserAccountStore脚本驱动以 Groovy 脚本作为查找逻辑脚本入参为[request, logger]两个对象返回PasswordlessUserAccount或空见 GroovyPasswordlessUserAccountStore.java。脚本位置通过cas.authn.passwordless.accounts.groovy.location指定适合快速实现复杂查找规则而无需重新编译 Java 代码。RestfulPasswordlessUserAccountStoreREST 数据源将查找行为委托给远程 REST 接口CAS 以配置的 HTTP 方法请求url / username附带username请求参数与自定义 headers响应体按PasswordlessUserAccount.class反序列化支持 HJSON 解析返回2xx且有实体时即视为命中见 RestfulPasswordlessUserAccountStore.java。相关配置包括cas.authn.passwordless.accounts.rest.urlhttps://idm.example.org/api/passwordless/account cas.authn.passwordless.accounts.rest.methodGET cas.authn.passwordless.accounts.rest.basic-auth-usernameuser cas.authn.passwordless.accounts.rest.basic-auth-passwordsecret cas.authn.passwordless.accounts.rest.headers... cas.authn.passwordless.accounts.rest.maximum-retry-attempts3编写并注册自定义存储完整实战下面以对接企业自有用户目录为场景演示完整的自定义实现步骤。假设你的用户目录存储在一个内存 Map 或数据库中需要根据用户名返回PasswordlessUserAccount。第一步实现接口在 CAS Overlay 中新建配置类与存储实现package org.example.cas.config; import org.apereo.cas.api.PasswordlessAuthenticationRequest; import org.apereo.cas.api.PasswordlessUserAccount; import org.apereo.cas.api.PasswordlessUserAccountStore; import org.apereo.cas.authentication.principal.PrincipalFactory; import java.util.Optional; public class MyDirectoryPasswordlessUserAccountStore implements PasswordlessUserAccountStore { private final UserDirectoryService userDirectoryService; public MyDirectoryPasswordlessUserAccountStore(final UserDirectoryService userDirectoryService) { this.userDirectoryService userDirectoryService; } Override public Optional? extends PasswordlessUserAccount findUser( final PasswordlessAuthenticationRequest request) throws Throwable { final String username request.getUsername(); final UserRecord record userDirectoryService.findByUsername(username); if (record null) { return Optional.empty(); } return Optional.of(PasswordlessUserAccount.builder() .username(record.getUsername()) .email(record.getEmail()) .phone(record.getPhoneNumber()) .name(record.getDisplayName()) .attributes(Map.of(memberOf, List.of(record.getGroups()))) .requestPassword(false) .build()); } Override public void reload() { userDirectoryService.refreshCache(); } }第二步声明 Bean 并注册配置类参照官方文档给出的 Bean 定义并在配置类上补充AutoConfiguration与EnableConfigurationPropertiespackage org.example.cas.config; import org.apereo.cas.api.PasswordlessUserAccountStore; import org.apereo.cas.configuration.CasConfigurationProperties; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.cloud.context.scope.refresh.RefreshScopeRefreshedEvent; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ScopedProxyMode; AutoConfiguration EnableConfigurationProperties(CasConfigurationProperties.class) public class CustomPasswordlessAccountStoreConfiguration { RefreshScope(proxyMode ScopedProxyMode.DEFAULT) Bean(name PasswordlessUserAccountStore.BEAN_NAME) public PasswordlessUserAccountStore passwordlessUserAccountStore( Qualifier(userDirectoryService) final UserDirectoryService userDirectoryService) { return new MyDirectoryPasswordlessUserAccountStore(userDirectoryService); } }要点说明Bean(name PasswordlessUserAccountStore.BEAN_NAME)显式使用标准 Bean 名称从而触发ConditionalOnMissingBean(name passwordlessUserAccountStore)条件使你的实现完全替换默认链式存储。RefreshScope(proxyMode ScopedProxyMode.DEFAULT)与 CAS 内部 Bean 定义保持一致外部配置变更触发上下文刷新时 Bean 可被重建CAS 官方文档 Configuration-Management-Extensions.md 亦推荐此写法。若你希望自定义存储作为补充数据源参与默认链式查找则去掉name属性改用如myPasswordlessUserAccountStore的自定义名称并可通过Order(...)控制查找顺序。第三步注册到 AutoConfiguration.imports创建或编辑src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件加入配置类全限定名org.example.cas.config.CustomPasswordlessAccountStoreConfiguration重启 CAS 后passwordlessUserAccountStore即为你自定义的实现。你可以通过 CAS 暴露的账户查询端点验证效果GET /cas/actuator/passwordless/account?usernamecasuser端点实现见 PasswordlessAuthenticationEndpoint.java。命中时返回账户 JSON200未命中返回 404同时端点会用默认PrincipalResolver解析用户并尝试将解析出的属性合并进账户attributes方便你观察最终账户数据。进阶账户定制器PasswordlessUserAccountCustomizer除存储实现外CAS 还提供了PasswordlessUserAccountCustomizer扩展点用于在存储查找完成后对账户做二次加工见 PasswordlessUserAccountCustomizer.java。它是一个Ordered接口customize(Optional? extends PasswordlessUserAccount)返回处理后的账户默认getOrder()为Ordered.HIGHEST_PRECEDENCE。SimplePasswordlessUserAccountStore的findUser在命中账户后会对所有非代理的 customizer 依次调用见 SimplePasswordlessUserAccountStore.java。CAS 内置的GroovyPasswordlessUserAccountCustomizer源码允许通过cas.authn.passwordless.core.passwordless-account-customizer-script.location指定 Groovy 脚本来动态修改账户属性脚本入参为[account, applicationContext, logger]。如果你的自定义存储想复用 customizer 机制可参考内置实现的做法在构造器中注入ListPasswordlessUserAccountCustomizer在findUser命中后遍历调用。存储查找链路与认证衔接为了完整理解自定义存储在整个无密码认证中的位置梳理关键调用链如下用户在登录页输入用户名CAS 触发无密码认证流程PasswordlessUserAccountStore.findUser(request)被调用可能经由ChainingPasswordlessAccountStore链式分发到你的自定义存储命中账户后CAS 依据账户的email/phone发送一次性令牌令牌由PasswordlessTokenRepository管理默认内存实现可配置 REST 后端见 CasPasswordlessAuthenticationAutoConfiguration.java用户提交令牌PasswordlessTokenAuthenticationHandler校验通过后完成认证账户attributes并入最终 Principal。从源码结构可以推断passwordlessUserAccountStoreBean 同时被认证处理器、端点等组件通过Qualifier(PasswordlessUserAccountStore.BEAN_NAME)引用因此只要标准 Bean 存在且行为正确整个认证链无需其他改动。小结自定义 Passwordless 用户账户存储是 CAS 无密码认证落地自有用户体系的标准做法核心就三步实现PasswordlessUserAccountStore接口、以标准 Bean 名称注册、通过AutoConfiguration.imports让 CAS 发现配置类。本文涉及的接口与实现均可在仓库中直接研读接口契约见 PasswordlessUserAccountStore.java账户模型见 PasswordlessUserAccount.java自动装配逻辑见 CasPasswordlessAuthenticationAutoConfiguration.java内置实现与测试见support/cas-server-support-passwordless-api/src/main/java/org/apereo/cas/impl/account/目录及 SimplePasswordlessUserAccountStoreTests.java。官方扩展机制的整体说明可参考 Configuration-Management-Extensions.md。赞分享后端认证鉴权单点登录【免费下载链接】casApereo CAS - Identity Single Sign On for all earthlings and beyond.项目地址https://gitcode.com/gh_mirrors/ca/cas点击查看免费下载相关推荐Apereo CAS 无密码认证账户存储Passwordless Account Stores完全指南Apereo CAS 无密码认证账户存储Passwordless Account Stores完全指南 导读 本文以 Apereo CAS 官方文档 Pas后端认证鉴权单点登录Apereo CAS LDAP 密码无感认证账户存储Passwordless Authentication Storage实战指南Apereo CAS LDAP 密码无感认证账户存储Passwordless Authentication Storage实战指南 导读 本文讲解 Aper后端认证鉴权单点登录Apereo CAS Surrogate 认证之 JSON 账户存储配置实战指南Apereo CAS Surrogate 认证之 JSON 账户存储配置实战指南 Surrogate 认证又称模拟/代管认证即“Web 版 sudo”允许后端认证鉴权单点登录上一篇motionEye 性能调优技巧提升视频流处理效率的终极指南下一篇终极指南如何在Termux上快速安装和修复Metasploit创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考