新闻详情

新闻详情

首页 / 资讯中心 / 详情

Spring Authorization Server自定义授权模式实现与配置迁移全解析

发布时间:2026/9/29 17:30:34来源:尧图网络
Spring Authorization Server自定义授权模式实现与配置迁移全解析
1. 项目背景与整体设计思路做 Spring Security OAuth2 开发的人大概率都有过这样的经历标准授权类型不够用。协议自带的 password、client_credentials、authorization_code 都是针对固定场景设计的但真实业务里总有一些“协议之外”的登录方式——短信验证码登录、第三方渠道快速登录、多因素校验后签发 token。这些需求落在 Spring Authorization Server 里就得走自定义授权模式。这篇文章我会把一个完整的自定义授权模式实现拆开讲从设计原理到 Spring Security 6 的配置迁移再到实际代码一次讲透。如果你正在做 Spring Boot 3 项目同时又在用 Spring Authorization Server 做统一认证这篇文章应该能帮你少踩不少坑。自定义授权模式要解决的核心问题是把“身份校验方式”和“token 签发机制”解耦。OAuth2 协议本身只关心 grant_type 是什么至于这个授权类型背后是密码、验证码还是人脸识别授权服务器全权交给对应的 AuthenticationProvider 处理。我们要做的就是利用这个开放机制把自定义的登录方式挂载到 token 端点上让客户端以标准 OAuth2 协议的形式拿到 access_token。1.1 为什么需要自定义授权模式拿一个真实场景举例。你现在要做一个 C 端产品的登录功能产品经理的要求很明确用户必须同时输入账号、密码和短信验证码。这个流程天然无法映射到标准的 password 授权模式因为 password 模式只接受 username 和 password 两个参数验证码塞进去也只是当作附加参数框架本身并不会触发验证码校验。你当然可以硬写在 password 模式的 AuthenticationProvider 里加一个 if 判断从 additionalParameters 里取出短信验证码调一次校验服务。看起来能跑但问题会在后续逐步暴露——当第二个登录方式比如第三方扫码出现时这个 Provider 会越来越臃肿当你想单独控制某种登录方式的客户端权限或 token 有效期时因为逻辑耦合在一起根本没法精细控制。自定义授权模式的价值就在这里。它为每一种登录方式定义一个独立的 grant_type每个 grant_type 对应一个独立的 AuthenticationConverter 和 AuthenticationProvider。授权服务器只负责协议解析和 token 下发身份校验逻辑全部由你自研的 Provider 处理。这样既保持了 OAuth2 协议的统一性又让认证逻辑按业务维度拆分后续加新登录方式不需要动旧代码。1.2 Spring Authorization Server 的扩展切入点Spring Authorization Server以下简称 SAS从 1.0 开始正式支持自定义授权类型扩展点集中在 tokenEndpoint 上。整个认证链路可以概括成三段第一段HTTP 请求到达 OAuth2TokenEndpointFilter。框架会先解析 client 认证信息把客户端身份放进请求 attribute 中。同时框架会把请求里的 grant_type 和默认支持的授权类型做匹配如果匹配不上就轮到自定义 AuthenticationConverter 上场。第二段AuthenticationConverter 负责把 HttpServletRequest 转换成内部的 AuthenticationToken 对象。这个 Token 对象继承 OAuth2AuthorizationGrantAuthenticationToken是自定义授权模式在框架内的形态载体。转换成功后框架把它交给 AuthenticationManager由其调度给对应的 AuthenticationProvider。第三段AuthenticationProvider 做真正的业务校验。校验通过后框架或者你自己生成 OAuth2Authorization 并调用 OAuth2TokenGenerator 签发 access_token 和 refresh_token最终包装成 OAuth2AccessTokenAuthenticationToken 返回。在三段链路中SAS 给你留了两个自定义点AuthenticationConverter 和 AuthenticationProvider。你只需要替换这两个组件并在 tokenEndpoint 配置里把它们注册上去剩下的 token 协议响应、客户端认证、异常处理全部由框架兜底。2. 授权类型设计与核心配置迁移2.1 自定义 Grant Type 与认证 Token 类的定义第一步是定义自定义授权类型标识。SAS 里的 AuthorizationGrantType 构造函数接受字符串所以你可以这样定义public final class CustomGrantTypes { public static final OAuth2AuthorizationGrantType VERIFY_CODE new OAuth2AuthorizationGrantType(verify_code); private CustomGrantTypes() { } }这里注意grant_type 字符串需要和客户端请求时传入的 grant_type 完全一致。客户端传 verify_code后端定义也得是 verify_code大小写敏感多个字符都不能差。接下来是自定义认证 Token 类。它必须继承 OAuth2AuthorizationGrantAuthenticationToken这个抽象类的构造函数有三个参数授权类型、客户端身份 Authentication、附加参数 Map。我额外在这个类里放入了业务需要的字段public class VerifyCodeGrantAuthenticationToken extends OAuth2AuthorizationGrantAuthenticationToken { private final String phone; private final String verifyCode; private final String channel; public VerifyCodeGrantAuthenticationToken(String phone, String verifyCode, String channel, Authentication clientPrincipal, MapString, Object additionalParameters) { super(CustomGrantTypes.VERIFY_CODE, clientPrincipal, additionalParameters); this.phone phone; this.verifyCode verifyCode; this.channel channel; } public String getPhone() { return phone; } public String getVerifyCode() { return verifyCode; } public String getChannel() { return channel; } }几个容易忽略的点super() 的第一个参数必须是前面定义的 VERIFY_CODE。SAS 在 token 端点匹配 Provider 时一部分依据就是 authorizationGrantType 是否相等。clientPrincipal 是 OAuth2ClientAuthenticationToken 类型里面携带着已通过客户端认证的 RegisteredClient。自定义 Provider 里要用它取客户端配置。additionalParameters 尽量在 Converter 里提前过滤干净把框架已消费的参数grant_type、client_id、client_secret剔掉避免后面业务参数解析时出现脏数据。2.2 Spring Boot 2 迁移到 Boot 3 的核心变化现在很多生产环境还在用 Spring Boot 2.x Spring Security 5.x但 Spring Boot 3 已经是大势所趋SAS 在 1.0 版本里对 Spring Security 6 的适配做了不少调整。迁移时我最先感受到的差异是配置方式的全面重构WebSecurityConfigurerAdapter 这个类被彻底移除以前习惯性继承它重写 configure(HttpSecurity http) 的老写法直接不可用。新的写法是声明 SecurityFilterChain Bean配合 Order 注解控制过滤链优先级。authorizeRequests() 改名 authorizeHttpRequests()lambda 式配置成为主流。antMatchers() 废弃改用 requestMatchers()并且需要显式传入 RequestMatcher 实例。and() 链式方法废弃推荐使用 http.with(...) 方式组合配置。对授权服务器来说最大的影响是配置结构变了。以前可以在一个 SecurityFilterChain 里既处理授权端点又处理普通请求现在更推荐的做法是把授权服务器端点和应用端点拆成两条 SecurityFilterChain一条 Order(1) 处理 /oauth2/** 相关端点另一条 Order(2) 或其他值处理普通业务接口。两条过滤链各司其职互不干扰。2.3 自定义 Converter 的参数解析与回归原则AuthenticationConverter 接口只有一个 convert(HttpServletRequest request) 方法实现并不复杂但有几个坑必须提前说清楚。首先Converter 只处理自己关心的 grant_type其他类型直接返回 null让框架继续尝试下一个 Converter。如果在这个阶段抛异常OAuth2TokenEndpointFilter 会直接把请求判定为无效请求返回 400 错误影响面很大。正确写法是在方法开头判断public class VerifyCodeGrantAuthenticationConverter implements AuthenticationConverter { Override public Authentication convert(HttpServletRequest request) { String grantType request.getParameter(OAuth2ParameterNames.GRANT_TYPE); if (!CustomGrantTypes.VERIFY_CODE.getValue().equals(grantType)) { return null; } String phone request.getParameter(phone); String verifyCode request.getParameter(verify_code); String channel request.getParameter(channel); if (StringUtils.hasText(phone) StringUtils.hasText(verifyCode)) { MapString, Object additionalParameters new HashMap(request.getParameterMap()); additionalParameters.remove(OAuth2ParameterNames.GRANT_TYPE); additionalParameters.remove(OAuth2ParameterNames.CLIENT_ID); additionalParameters.remove(OAuth2ParameterNames.CLIENT_SECRET); OAuth2ClientAuthenticationToken clientPrincipal getClientPrincipal(request); return new VerifyCodeGrantAuthenticationToken(phone, verifyCode, channel, clientPrincipal, additionalParameters); } return null; } private OAuth2ClientAuthenticationToken getClientPrincipal(HttpServletRequest request) { Authentication authentication (Authentication) request.getUserPrincipal(); if (authentication instanceof OAuth2ClientAuthenticationToken) { return (OAuth2ClientAuthenticationToken) authentication; } throw new OAuth2AuthenticationException(new OAuth2Error(OAuth2ErrorCodes.INVALID_REQUEST)); } }注意 clientPrincipal 的获取方式。请求经过 OAuth2TokenEndpointFilter 时框架会先做一次客户端认证认证结果存放在 request 的 attribute 里。直接通过 getUserPrincipal() 就能拿到 OAuth2ClientAuthenticationToken不需要自己从 Authorization 头里解析 Basic 凭证更不需要手动校验客户端密码。这块容易重复造轮子实际没必要。3. 核心 Provider 实现与完整代码走读3.1 基于 OAuth2AuthorizationGrantAuthenticationProvider 的推荐写法SAS 1.0 之后提供了一个抽象基类 OAuth2AuthorizationGrantAuthenticationProvider它为自定义授权类型做了完整的模板封装。这个基类已经帮你处理好了客户端认证校验、token 生成、授权保存、异常转换等一堆琐碎逻辑你只需要实现一个抽象方法protected abstract Authentication getAuthentication(Authentication authentication, RegisteredClient registeredClient);我强烈建议使用这个基类而不是从零实现 AuthenticationProvider 接口。从接口写虽然自由度高但容易漏掉 refresh_token 的生成条件、授权记录的状态管理这些细节生产环境会埋雷。基类的封装逻辑和框架内置 Provider 保持一致行为最可控。3.2 完整 Provider 代码走读以短信验证码登录为例自定义 Provider 的完整实现如下public class VerifyCodeGrantAuthenticationProvider extends OAuth2AuthorizationGrantAuthenticationProvider { private final UserDetailsService userDetailsService; private final VerifyCodeService verifyCodeService; public VerifyCodeGrantAuthenticationProvider(OAuth2AuthorizationService authorizationService, OAuth2TokenGenerator tokenGenerator, UserDetailsService userDetailsService, VerifyCodeService verifyCodeService) { super(authorizationService, tokenGenerator); this.userDetailsService userDetailsService; this.verifyCodeService verifyCodeService; } Override protected Authentication getAuthentication(Authentication authentication, RegisteredClient registeredClient) { VerifyCodeGrantAuthenticationToken verifyCodeToken (VerifyCodeGrantAuthenticationToken) authentication; String phone verifyCodeToken.getPhone(); String verifyCode verifyCodeToken.getVerifyCode(); // 1. 校验验证码 if (!verifyCodeService.verify(phone, verifyCode)) { throw new OAuth2AuthenticationException(new OAuth2Error(invalid_verify_code), 验证码错误或已过期); } // 2. 加载用户信息 UserDetails userDetails userDetailsService.loadUserByUsername(phone); if (userDetails null) { throw new OAuth2AuthenticationException(new OAuth2Error(user_not_found), 用户不存在); } // 3. 构造已认证的 principal交由基类完成 token 下发 return new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); } }这里 getAuthentication 方法的返回对象会被基类当作已认证的用户主体写入授权记录并作为 token 的 principal。有几个要点需要留意返回的 Authentication 必须是已认证状态isAuthenticated() 返回 true否则基类会在后续构建授权时抛异常。异常类型统一抛 OAuth2AuthenticationException基类会把它转成符合 OAuth2 规范的错误响应体客户端拿到的就是标准的 error 字段而不是一坨奇怪的堆栈信息。基类内部会根据 registeredClient 的配置决定是否生成 refresh_token所以你只要保证授权类型相关的客户端配置正确即可不用自己判断。3.3 token 生成器的装配基类构造函数需要传入 OAuth2TokenGenerator这个对象用来实际生成 access_token 和 refresh_token。SAS 提供了 DelegatingOAuth2TokenGenerator可以按顺序尝试多个生成器。最简单的装配方式是把访问令牌生成器和刷新令牌生成器组合起来Bean public OAuth2TokenGenerator tokenGenerator() { OAuth2AccessTokenGenerator accessTokenGenerator new OAuth2AccessTokenGenerator(); OAuth2RefreshTokenGenerator refreshTokenGenerator new OAuth2RefreshTokenGenerator(); DelegatingOAuth2TokenGenerator delegatingGenerator new DelegatingOAuth2TokenGenerator( accessTokenGenerator, refreshTokenGenerator ); return delegatingGenerator; }这种配置生成的 access_token 是随机不透明字符串适合需要自研校验逻辑的场景。如果你需要 JWT 格式的 token则需要额外装配 JwtEncoder 和 JwtGenerator并把 JwtGenerator 放在 DelegatingOAuth2TokenGenerator 列表最前面。注意 JwtGenerator 内部需要配置加密密钥常见做法是注入 JWKSource用 RSA 或 HMAC 密钥对 token 签名。这块建议根据团队是否已经接入 JWT 生态来决定不透明 token 在简单场景下反而更省事。4. Spring Security 6 授权服务器配置与注册4.1 授权服务器 SecurityFilterChain 完整配置配置这一步是最容易出错的。Spring Security 6 时代授权服务器的配置集中在 authorizationServerSecurityFilterChain 这个方法里Configuration EnableWebSecurity public class AuthorizationServerConfig { Bean Order(1) public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http, OAuth2AuthorizationService authorizationService, OAuth2TokenGenerator tokenGenerator, UserDetailsService userDetailsService, VerifyCodeService verifyCodeService) throws Exception { OAuth2AuthorizationServerConfigurer authorizationServerConfigurer new OAuth2AuthorizationServerConfigurer(); http .securityMatcher(authorizationServerConfigurer.getEndpointsMatcher()) .with(authorizationServerConfigurer, customizer - { customizer .tokenEndpoint(tokenEndpoint - tokenEndpoint .authenticationConverter(new VerifyCodeGrantAuthenticationConverter()) .authenticationProvider(new VerifyCodeGrantAuthenticationProvider( authorizationService, tokenGenerator, userDetailsService, verifyCodeService) ) ); }) .authorizeHttpRequests(authorize - authorize.anyRequest().authenticated()); return http.build(); } Bean Order(2) public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(authorize - authorize .requestMatchers(/login/**, /error).permitAll() .anyRequest().authenticated()) .formLogin(form - form.loginPage(/login).permitAll()); return http.build(); } }默认的/oauth2/token端点、授权码端点、token 校验端点都属于 authorizationServerConfigurer.getEndpointsMatcher() 匹配范围内所以你不需要手动为它们设置权限规则securityMatcher 会精确匹配。这条过滤链后面的 authorizeHttpRequests 配置主要是兜底保证其他端点不会漏放。4.2 客户端注册与授权模式启用自定义授权模式对应的客户端必须在 RegisteredClientRepository 中配置启用 verify_code 授权类型否则 Provider 基类校验客户端授权类型时会直接拒绝。典型的客户端注册如下Bean public RegisteredClientRepository registeredClientRepository() { RegisteredClient verifyCodeClient RegisteredClient .withId(UUID.randomUUID().toString()) .clientId(web-app) .clientSecret({noop}web-secret) .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC) .authorizationGrantType(CustomGrantTypes.VERIFY_CODE) .authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN) .scope(read) .scope(write) .tokenSettings(TokenSettings.builder() .accessTokenTimeToLive(Duration.ofHours(12)) .build()) .build(); return new InMemoryRegisteredClientRepository(verifyCodeClient); }这里额外配了 REFRESH_TOKEN 授权类型。基类生成 refresh_token 需要两个条件一是客户端允许 REFRESH_TOKEN 授权类型二是 token 生成器列表里包含 OAuth2RefreshTokenGenerator。少了任何一个刷新令牌都不会下发。4.3 旧版本配置迁移的对照表如果你是从 Spring Boot 2 项目迁过来的下面这个表基本能覆盖大部分配置替换场景旧配置/类新配置/类备注WebSecurityConfigurerAdapterSecurityFilterChain Bean废弃继承改用 Bean 声明authorizeRequests()authorizeHttpRequests()方法名变更lambda 风格antMatchers(/x)requestMatchers(/x)传字符串需包一层 RequestMatcher 或直接传路径http.and()http.with()链式配置重构EnableResourceServer手动配置 BearerTokenAuthenticationFilterSpring Security 6 不再提供注解PasswordEncoder 的 {id} 前缀仍旧支持生产环境建议 BCryptPasswordEncoderOAuth2AuthorizationServerConfigurer.apply(http)http.with(configurer, customizer)1.0 后推荐 with 写法这里需要提醒一点如果项目里同时存在资源服务器和授权服务器逻辑新版本更推荐拆成独立的服务部署或者至少拆成不同的 SecurityFilterChain。两条链之间的 Matcher 如果不小心重叠会出现过滤器顺序混乱、请求被错误链路拦截的问题。我建议在每条链上通过 securityMatcher 明确划定管辖范围宁可范围小一点也不要含糊。5. 常见问题与排查技巧实录5.1 客户端认证失败RegisteredClient 为 null这是自定义授权模式里最常见的报错错误信息一般是 OAuth2AuthenticationException: [invalid_client] Client authentication failed 或者 Provider 内拿到 clientPrincipal 后 registeredClient 为 null。排查思路分两步。先看客户端认证本身有没有通过。用 curl 测试时必须保证 Authorization 头里携带正确的 Basic 凭证也就是 clientId:clientSecret 经过 Base64 编码。如果你的客户端注册配置里 clientSecret 是明文存储记得加 {noop} 前缀否则 DelegatingPasswordEncoder 会认为加密格式不匹配。再看客户端是否启用了自定义授权类型。RegisteredClient 的 authorizationGrantType 列表里必须包含 verify_code漏掉这一步即使客户端认证成功基类校验授权类型时也会把你拦下来。5.2 token 生成为 null但业务校验已经通过如果你在集成测试中发现业务校验都正常但返回的 access_token 是 null问题几乎都出在 token 生成器装配上。DelegatingOAuth2TokenGenerator 是按顺序尝试的如果第一个生成器返回 null它不会自动选择下一个而是直接结束。举一个真实踩过的例子我在项目里只配置了 JwtGenerator但 JwtEncoder 的 JWKSource 没有正确初始化导致 JwtGenerator 内部抛异常或返回 null。表面上看是 token 生成失败实际上根因是签名密钥配置缺失。排查时先确认 tokenGenerator 这个 Bean 被正确注入到 Provider 中再确认加密相关组件是否初始化成功可以在测试里单独调用 tokenGenerator.generate() 打印结果。5.3 自定义 Provider 注册了但请求还是 400这种情况通常是 AuthenticationConverter 没有挂载上去。tokenEndpoint 配置里 provider 和 converter 是两个独立的注册项少了任何一个框架都会认为 verify_code 是不可识别的授权类型返回 OAuth2ErrorCodes.UNSUPPORTED_GRANT_TYPE。另外注意 Converter 的注册顺序。框架执行时会按注册顺序逐个调用 converter如果你同时注册了多个自定义 converter要确保每个 converter 只处理自己的 grant_type相互之间不能有重叠匹配。5.4 迁移后的编译报错速查Spring Security 6 升级过程中最常见的一批编译报错可以快速对照解决编译错误原因与处理cannot find symbol: WebSecurityConfigurerAdapter类已移除改用 SecurityFilterChain BeanauthorizeRequests() is deprecated改为 authorizeHttpRequests()antMatchers() is deprecated改为 requestMatchers()注意参数类型and() cannot be resolved链式调用重构使用 lambda 或 http.with()OAuth2AuthorizationServerConfigurer cannot be applied to HttpSecurity1.0 后使用 http.with(configurer, customizer) 或 http.apply(configurer) 的旧写法需替换还有一个容易被忽略的点Spring Boot 3 要求 JDK 17 以上如果你从 JDK 8 直接升级除了 Spring Security 的 API 调整还要处理 javax 到 jakarta 命名空间的迁移HttpServletRequest 等相关 import 都要改成 jakarta.servlet。这个工作量往往比想象中大建议在排期时预留三天左右做全量回归测试。5.5 排查技巧临时打开安全日志遇到定位困难的问题第一步不是猜而是把日志级别调低。在 application.yml 里临时加入logging: level: org.springframework.security: DEBUG org.springframework.security.oauth2.server.authorization: DEBUGDEBUG 日志会打印出 token 端点收到请求后的每一步处理细节包括 converter 是否返回 null、provider 匹配是否命中、token 生成是否成功。我实际排查过不下二十个自定义授权类型相关的问题90% 靠日志就能定位。不要上来就断点调试生产环境也没法这么干。日志里重点关注三条关键链路OAuth2TokenEndpointFilter 的 doFilter 日志、AuthenticationManager 调用 Provider 的日志、以及 OAuth2TokenGenerator 生成结果的日志。看到这三处链路都畅通整个流程基本就通了。6. 最后补充一个容易踩的坑在收尾之前说一个我第二次做自定义授权模式时才意识到的细节——authorization_code 和 refresh_token 这两个标准授权类型本身也算“自定义授权模式”的变体。SAS 1.0 的 OAuth2AuthorizationGrantAuthenticationProvider 基类设计思路其实就是从授权码模式里抽象出来的它的很多行为比如是否生成刷新令牌、授权记录的状态维护都以授权码机制作为模板。这意味着你在实现自定义 Provider 时最大的风险不是写不出来而是“过度定制”。比如有人喜欢直接在 Provider 里手动调用 authorizationService.save()手写 authorizationBuilder搞得代码量翻倍。基类把这套流程已经标准化了你能少写就少写把精力集中在 getAuthentication 方法里做业务校验。还有一点自定义授权模式返回的 token 默认不会携带用户信息。客户端拿到 access_token 后需要通过调用 /userinfo 端点或自研的资源服务器校验逻辑来获取用户详情。如果你的 token 是自包含的 JWT可以在 JwtGenerator 的 claims 定制器里加入用户维度信息如果用的是不透明 token建议业务系统内部再维护一份 token 到用户信息的映射。这两种方式我都在生产环境中用过简单场景推荐后者能少处理一套 JWT 密钥轮换和 claim 兼容的问题复杂多服务场景再考虑引入 JWT。关于自定义授权模式的实现这篇就从设计思路、核心代码写到配置迁移和问题排查。最后再说一句掏心窝的话这个方案看起来代码量不大但真正能一次跑通的比例不高。大部分时间都耗在配置不对、组件没装配、认证链路细节不匹配这些环境问题上建议你按照我上面的顺序先把 Converter 和 Provider 在单测里分别验证再接入配置最后做端到端测试。编码顺序对了调通的概率能高一大截。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

计算机毕业设计之基于springboot的招商管理系统 2026/9/29 21:07:13

计算机毕业设计之基于springboot的招商管理系统

二十一世纪我们的社会进入了信息时代,信息管理系统的建立,大大提高了人们信息化水平。传统的管理方式对时间、地点的限制太多,而在线管理系统刚好能满足这些需求,在线管理系统突破了传统管理方式的局限性。于是本文针对这一需求设…

阅读更多 →
测试用例属性设计:从分层模型到pairwise正交组合的完整指南 2026/9/29 21:07:13

测试用例属性设计:从分层模型到pairwise正交组合的完整指南

1. 先对齐语境:你说的“case”,到底是哪一个 case很多人在聊“一个 case 由哪些属性组成”的时候,讨论到一半就变味了,因为“case”这个词实在太容易踩进不同语境。写代码的人脑子里的第一反应是switch case、CASE WHEN这类语法关…

阅读更多 →
高性能创作电脑到底怎么影响你的成片质量 2026/9/29 21:07:13

高性能创作电脑到底怎么影响你的成片质量

你有没有遇到过这种情况:明明用的是高端显卡,导出的视频在客户屏幕上却偏色严重;或者渲染一小时的工程,刚保存就蓝屏崩溃?很多人把问题归咎于软件或运气,其实根源在于整机硬件协同逻辑被忽视了。尤其是在专…

阅读更多 →
case属性管理之道:分层、正交与组合的工程实践 2026/9/29 21:07:13

case属性管理之道:分层、正交与组合的工程实践

你有没有过这种体验:一个看起来很小的case,改起来却要牵扯十几个地方;一张表的属性加了又加,最后堆到两三百个字段;人人都说要分层、要正交、要组合,但真到动手时,没人说得清一个case的属性到底…

阅读更多 →
金蝶ERP插件开发实战:从事件机制到二次开发落地 2026/9/29 21:07:13

金蝶ERP插件开发实战:从事件机制到二次开发落地

做金蝶ERP实施和开发这些年,我接过不少客户的二次开发需求,最开始大家口中的“插件开发”往往指的就是在KingdeeERP上扩展功能。真正上手之后会发现,它跟你平时做的普通.NET开发差别不小,界面逻辑、业务校验、数据流转、部署发布&…

阅读更多 →
AI Compass前沿速览:Anthropic Claude Computer Use 开发者最佳实践指南与 Lumen Flow 同周登场,AGenUI、General365 热词——TaoTok 2026/9/29 21:07:06

AI Compass前沿速览:Anthropic Claude Computer Use 开发者最佳实践指南与 Lumen Flow 同周登场,AGenUI、General365 热词——TaoTok

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉