授权服务模块基于 Spring Authorization Server,提供完整的 OAuth2/OIDC 授权服务器功能。
架构概述
授权服务遵循标准的 OAuth2 授权码流程,同时扩展了多种认证方式:
-
认证层:支持授权码、密码、客户端凭证、短信验证码、图形验证码、小程序等多种认证方式
-
Token 层:支持 JWT 和 Opaque Token,可自定义 Token 生成和校验逻辑
-
客户端管理:通过 RegisteredClientRepository 管理 OAuth2 客户端配置,支持数据库持久化
-
用户管理:通过 UserInfo 接口自定义用户信息模型
-
授权服务:支持 Redis 和内存两种 OAuth2AuthorizationService 后端实现
核心概念
-
RegisteredClient:OAuth2 客户端配置,包含客户端ID、密钥、授权类型、重定向URI等
-
UserInfo:用户信息接口,自定义用户对象需实现此接口
-
CustomService:自定义验证服务接口,用于自定义认证逻辑
-
CaptchaVerificationService:验证码校验服务接口
-
IOauth2ClientService:OAuth2 客户端服务接口,用于客户端的增删改查
-
Oauth2Client:客户端实体接口,定义了客户端配置的字段规范
-
Oauth2ClientConvertor:客户端实体转换器,实现 Oauth2Client 与 RegisteredClient 的相互转换
支持的授权类型
授权类型 |
说明 |
authorization_code |
授权码模式(OAuth2 标准流程) |
client_credentials |
客户端凭证模式(服务间调用) |
refresh_token |
刷新令牌(延长会话) |
password |
密码模式(自定义扩展) |
custom |
自定义模式 |
sms |
短信验证码登录(自定义扩展) |
mini_program |
小程序登录(自定义扩展) |
授权类型通过 ThinkBridgeOAuth2AuthorizationServerConfiguration 中注册的 AuthenticationConverter 实现,每种扩展授权类型对应一个转换器,在 Token 端点自动匹配。
配置属性
授权服务器配置
所有授权服务器配置前缀为 hink.auth.server:
属性 |
默认值 |
说明 |
think.auth.server.enabled |
true |
启用授权服务器 |
think.auth.server.init-client |
false |
启动时从配置初始化客户端 |
think.auth.server.captcha.enable |
true |
启用验证码功能 |
think.auth.server.captcha.close |
false |
关闭验证码校验 |
think.auth.server.sms.enable |
true |
启用短信验证码登录 |
think.auth.server.custom.enable |
true |
启用自定义认证 |
think.auth.server.mini-program.enable |
true |
启用小程序登录 |
Token 自定义
框架提供 ThinkbridgeOAuth2TokenCustomizer 自动将 UserInfo 中的扩展信息注入到 JWT Token 的 Claims 中。
扩展信息的前缀通过 hink.auth.userinfo-ext-prefix 配置(默认值参考 UserInfo 接口常量),生成的 Token 中将包含 {prefix}{key} 格式的自定义 Claims。
授权服务后端
框架提供两种 OAuth2AuthorizationService 实现:
-
RedisOAuth2AuthorizationService:基于 Redis 的授权信息存储,支持集群部署,自动管理 Token 过期
-
InMemoryOAuth2AuthorizationService:基于内存的授权信息存储,适用于单机开发环境
当引入 spring-data-redis 依赖并配置 Redis 连接后,自动使用 Redis 实现。
Gradle 引用
// 授权服务基础包
implementation "com.luamas.thinkbridge:authorization-server-spring-boot-starter"
// 资源保护
implementation "com.luamas.thinkbridge:authorization-resource-spring-boot-starter"
完整代码如下:
plugins {
id 'java'
id 'org.springframework.boot' version '4.1.1'
id 'io.spring.dependency-management' version '1.1.7'
}
group = 'com.thinkbridge.demo'
version = '0.0.1-SNAPSHOT'
java {
sourceCompatibility = '25'
}
repositories {
mavenCentral()
}
ext {
springCloudVersion = "2025.1.3"
thinkBridgeVersion = '2025.1.2'
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
dependencies {
implementation 'com.luamas.thinkbridge:authorization-server-spring-boot-starter'
implementation 'com.luamas.thinkbridge:authorization-resource-spring-boot-starter'
implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'
implementation "org.springframework.boot:spring-boot-starter-actuator"
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
dependencyManagement {
resolutionStrategy {
cacheChangingModulesFor(0, 'seconds')
}
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
mavenBom "com.luamas.thinkbridge:thinkbridge-bom:${thinkBridgeVersion}"
}
}
test {
useJUnitPlatform()
}
客户端仓库
授权服务器支持将 OAuth2 客户端信息存储到数据库中,通过实现 RegisteredClientRepository 接口来自定义客户端信息的持久化方式。
接口说明
Oauth2Client 接口定义了客户端实体需要实现的字段规范,包含客户端ID、密钥、授权类型、重定向URI、Token 设置等核心字段。
Oauth2ClientConvertor 工具类负责 Oauth2Client 与 RegisteredClient 之间的相互转换,包括:
-
toRegisteredClient():将 Oauth2Client 实体转换为 RegisteredClient 对象,用于向 Spring Authorization Server 注册客户端
-
fromRegisteredClient():将 RegisteredClient 转换为 Oauth2Client 实体,用于持久化存储
转换过程中自动处理授权类型、认证方法、Token 设置等复杂对象的序列化/反序列化。
实现步骤
1. 自定义客户端仓库
实现 RegisteredClientRepository 接口,从数据库加载客户端信息:
package com.thinkbridge.demo.auth.thinkbridge;
import com.luamas.thinkbridge.common.security.oauth2.IRegisteredClientService;
import com.luamas.thinkbridge.common.security.oauth2.Oauth2Client;
import com.luamas.thinkbridge.common.security.oauth2.Oauth2ClientConvertor;
import com.thinkbridge.demo.auth.service.IOauth2ClientService;
import lombok.RequiredArgsConstructor;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
import java.util.Collection;
import java.util.function.Function;
@RequiredArgsConstructor
public class MyRegisteredClientRepository implements RegisteredClientRepository, IRegisteredClientService<String> {
private final IOauth2ClientService myOauth2ClientService;
@Override
public void save(RegisteredClient registeredClient) {
MyOauth2Client myOauth2Client = this.myOauth2ClientService.lambdaQuery().eq(Oauth2Client::getClientId, registeredClient.getClientId()).one();
MyOauth2Client newOauth2Client = new MyOauth2Client();
newOauth2Client = Oauth2ClientConvertor.fromRegisteredClient(registeredClient, newOauth2Client);
if (myOauth2Client != null) {
newOauth2Client.setId(myOauth2Client.getId());
}
this.myOauth2ClientService.saveOrUpdate(newOauth2Client);
}
@Override
public RegisteredClient findById(String id) {
Oauth2Client myOauth2Client = this.myOauth2ClientService.getById(id);
return Oauth2ClientConvertor.toRegisteredClient(myOauth2Client);
}
@Override
public RegisteredClient findByClientId(String clientId) {
Oauth2Client myOauth2Client = this.myOauth2ClientService.lambdaQuery().eq(Oauth2Client::getClientId, clientId).one();
return Oauth2ClientConvertor.toRegisteredClient(myOauth2Client);
}
@Override
public boolean removeById(String id) {
return myOauth2ClientService.removeById(id);
}
@Override
public boolean removeByIds(Collection<String> ids) {
return myOauth2ClientService.removeByIds(ids);
}
}
2. 客户端服务接口
IOauth2ClientService 接口继承 mybatis-plus 的 IService 接口:
package com.thinkbridge.demo.auth.service;
import com.baomidou.mybatisplus.spring.service.IService;
import com.thinkbridge.demo.auth.thinkbridge.MyOauth2Client;
public interface IOauth2ClientService extends IService<MyOauth2Client> {
}
3. 客户端服务实现
IOauth2ClientService 的实现类:
package com.thinkbridge.demo.auth.service;
import com.baomidou.mybatisplus.spring.service.impl.ServiceImpl;
import com.thinkbridge.demo.auth.thinkbridge.MyOauth2Client;
import com.thinkbridge.demo.auth.mapper.MyOauth2ClientMapper;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
@Service
public class Oauth2ClientServiceImp extends ServiceImpl<MyOauth2ClientMapper, MyOauth2Client> implements IOauth2ClientService {
private static final PasswordEncoder passwordEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
@Override
public boolean save(MyOauth2Client myOauth2Client) {
if (!myOauth2Client.getClientSecret().startsWith("{")) {
myOauth2Client.setClientSecret(passwordEncoder.encode(myOauth2Client.getClientSecret()));
}
return super.save(myOauth2Client);
}
}
4. 客户端实体类
MyOauth2Client 实体类需要实现 com.luamas.thinkbridge.common.security.oauth2.Oauth2Client 接口:
package com.thinkbridge.demo.auth.thinkbridge;
import com.baomidou.mybatisplus.annotation.*;
import com.luamas.thinkbridge.common.security.oauth2.Oauth2Client;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDateTime;
@Getter
@Setter
@ToString
@TableName("sys_oauth2_client")
public class MyOauth2Client implements Oauth2Client<String>, Serializable {
@Serial
private static final long serialVersionUID = 1L;
/
* ID
*/
@TableId(value = "id", type = IdType.AUTO)
private String id;
/
* 客户端ID
*/
private String clientId;
/
* 颁发时间
*/
private LocalDateTime clientIdIssuedAt;
/
* 客户端密钥
*/
private String clientSecret;
/
* 密钥过期时间
*/
private LocalDateTime clientSecretExpiresAt;
/
* 客户端名称
*/
private String clientName;
/
* 客户端认证方式,逗号分隔
*/
private String clientAuthenticationMethods;
/
* 授权方式,逗号分隔
*/
private String authorizationGrantTypes;
/
* 重定向url,逗号分隔
*/
private String redirectUris;
/
* 退出后的重定向url,逗号分隔
*/
private String postLogoutRedirectUris;
/
* 授权范围,逗号分隔
*/
private String scopes;
/
* 客户端配置,json字符串
*/
private String clientSettings;
/
* token配置,json字符串
*/
private String tokenSettings;
/
* 创建人
*/
@TableField(value="create_by",fill = FieldFill.INSERT)
private String createBy;
/
* 创建时间
*/
@TableField(value="create_time",fill = FieldFill.INSERT)
private LocalDateTime createTime;
/
* 更新人
*/
@TableField(value="update_by",fill = FieldFill.INSERT_UPDATE)
private String updateBy;
/
* 更新时间
*/
@TableField(value="update_time",fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
/
* 是否删除 0 否 1 是
*/
@TableLogic(value = "false", delval = "true")
@TableField(value="is_delete")
private Boolean deleted;
}
5. 用户实体类
MyOauth2User 实体类:
package com.thinkbridge.demo.auth.thinkbridge;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.io.Serial;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
@Getter
@Setter
@ToString
@Builder
@TableName(value = "sys_user_info")
public class MyOauth2User implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Long id;
@TableField(value = "status")
private Integer status; // 账号状态:1启用 2禁用 3预留
@TableField(value = "user_account")
private String userAccount; // 用户名,唯一
@TableField(value = "user_password")
private String userPassword; // 用户密码
private String wxUnionId;
private String wxOpenId;
//租户id
private Long tenantId;
@TableLogic
private Integer deleted;
/
* 创建人
*/
@TableField(value="create_by",fill = FieldFill.INSERT)
private String createBy;
/
* 创建时间
*/
@TableField(value="create_time",fill = FieldFill.INSERT)
private Date createTime;
/
* 更新人
*/
@TableField(value="update_by",fill = FieldFill.INSERT_UPDATE)
private String updateBy;
/
* 更新时间
*/
@TableField(value="update_time",fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
}
| Oauth2ClientConvertor 已内置 Jackson 序列化配置,自动处理 ClientSettings 和 TokenSettings 的 JSON 序列化,确保自定义配置项(如 Token 格式、AccessToken 有效期等)在持久化过程中不丢失。 |
自定义用户对象
授权服务器支持自定义用户对象,通过实现 com.luamas.thinkbridge.common.security.vo.UserInfo 接口来扩展用户信息字段。
接口说明
UserInfo 接口定义了用户信息的基本契约,实现该接口后,自定义的用户对象将替代默认的用户信息模型。
UserInfo 接口包含以下核心方法:
-
用户基本信息:获取用户名、密码、权限列表等
-
getExtend():返回扩展信息 Map,这些信息会自动注入到 JWT Token 的 Claims 中
扩展信息注入
UserInfo 的 getExtend() 方法返回的扩展信息,会通过 ThinkbridgeOAuth2TokenCustomizer 自动注入到 JWT Token 的 Claims 中。
注入规则:
-
Claims 的 key 格式为:{prefix}{extendKey}
-
前缀通过 think.auth.userinfo-ext-prefix 配置(默认值参考 UserInfo 接口常量)
-
例如:扩展信息包含 { "department": "engineering" },前缀为 ext_,则 JWT 中会增加 ext_department Claim
这种设计使得在不修改 Token 自定义逻辑的情况下,通过 UserInfo 实现即可灵活控制 JWT 中的自定义字段。
实现示例
以下示例展示 com.thinkbridge.demo.auth.thinkbridge.MyUserInfo 类的实现:
package com.thinkbridge.demo.auth.thinkbridge;
import com.luamas.thinkbridge.common.security.vo.UserInfo;
import lombok.Getter;
import lombok.Setter;
import org.springframework.security.core.GrantedAuthority;
import java.util.*;
@Getter
@Setter
public class MyUserInfo implements UserInfo {
private String userId;
private String name;
private Collection<? extends GrantedAuthority> authorities = new HashSet<>();
private Collection<String> roleIds = new HashSet<>();
private Map<String, Object> extend = new HashMap<>();
}
| 自定义用户对象需要实现 UserInfo 接口的所有方法,包括获取用户名、权限列表等核心信息。扩展信息可以通过 getExtend() 返回任意键值对。 |
自定义验证服务
授权服务器支持自定义验证服务,通过实现 com.luamas.thinkbridge.common.security.authentication.custom.CustomService 接口来扩展认证逻辑。
接口说明
CustomService 接口用于自定义认证流程,当内置的授权类型(如 uthorization_code、client_credentials 等)无法满足需求时,可通过实现此接口添加自定义的认证方式。
CustomService 接口包含以下核心方法:
-
识别认证类型:区分不同类型的自定义认证请求
-
执行认证逻辑:验证用户凭证,返回用户信息
-
返回 UserInfo:认证成功后返回实现了 UserInfo 接口的用户对象
自动注册
ThinkBridgeGlobalAuthenticationConfigurer 会自动检测 Spring 容器中是否存在 CustomService 类型的 Bean:
-
如果存在,自动注册 CustomAuthenticationProvider
-
如果不存在,跳过自定义认证逻辑的注册
同时需要启用 think.auth.server.custom.enable=true(默认启用)。
实现示例
以下示例展示 com.thinkbridge.demo.auth.thinkbridge.MyCustomService 类的实现:
package com.thinkbridge.demo.auth.thinkbridge;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.symmetric.AES;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.luamas.thinkbridge.common.security.authentication.custom.CustomService;
import com.luamas.thinkbridge.common.security.vo.UserInfo;
import com.thinkbridge.demo.auth.mapper.MyOauth2UserMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.stereotype.Service;
import java.nio.charset.StandardCharsets;
import java.util.*;
@Service
@RequiredArgsConstructor
@Slf4j
@ConditionalOnProperty(prefix = "demo.jwk.set.aes", name = "key", matchIfMissing = false)
public class MyCustomService implements CustomService {
private final MyOauth2UserMapper myOauth2UserMapper;
@Value("${demo.jwk.set.aes.key}")
private String secretKey;
public static void main(String[] args) {
AES aes = SecureUtil.aes("gJ0cD3bH0dK0hD2a".getBytes(StandardCharsets.UTF_8));// 创建AES解密器
System.out.println(aes.encryptHex("admin_7771"));
}
@Override
public UserInfo verify(Object principal, Object credentials) {
AES aes = SecureUtil.aes(secretKey.getBytes(StandardCharsets.UTF_8));// 创建AES解密器
String username = null;
Long tenantId = null;
if (principal != null && principal instanceof String) {
tenantId = Long.valueOf(principal.toString());
}
// if (tenantId == null) {
// throw new BadCredentialsException("tenantId不能为空");
// }
if (credentials instanceof String) {
try {
username = aes.decryptStr(credentials.toString());
} catch (Exception e) {
log.warn("秘钥错误:{},{}", tenantId, username);
throw new BadCredentialsException("秘钥错误");
}
}
if (StringUtils.isBlank(username)) {
log.info("秘钥内容错误:{},{}", tenantId, username);
throw new BadCredentialsException("秘钥内容错误");
}
MyOauth2User myOauth2User = myOauth2UserMapper.selectOne(new LambdaQueryWrapper<MyOauth2User>().eq(MyOauth2User::getUserAccount, username).ne(MyOauth2User::getStatus, 3));
if(myOauth2User == null){
log.info("用户错误:{},{}", tenantId, username);
throw new BadCredentialsException("用户错误");
}
if(tenantId!= null && !tenantId.equals(myOauth2User.getTenantId())){
log.info("sid越权:{},{}", tenantId, username);
throw new BadCredentialsException("tenantId越权");
}
Map<String, Object> map = new HashMap<>();
map.put("uid", myOauth2User.getId());
map.put("tenant_id", myOauth2User.getTenantId());
map.put("name", myOauth2User.getUserAccount());
MyUserInfo myUserInfo = new MyUserInfo();
myUserInfo.setUserId(myOauth2User.getId().toString());
myUserInfo.setName(myOauth2User.getUserAccount());
myUserInfo.setAuthorities(new ArrayList<>());
myUserInfo.setRoleIds(new ArrayList<>());
myUserInfo.setExtend(map);
return myUserInfo;
}
}
| 自定义验证服务适用于需要集成第三方认证、短信验证码登录、微信扫码登录等场景。框架会根据 token 端点请求中的 grant_type 参数自动匹配对应的认证处理器。 |
验证码校验服务
授权服务器支持在登录流程中集成验证码校验,通过实现 CaptchaVerificationService 接口来自定义验证码校验逻辑。
接口说明
CaptchaVerificationService 接口定义了验证码校验的契约,实现该接口并将其注册为 Spring Bean,框架会自动在登录流程中调用。
CaptchaVerificationService 包含以下核心方法:
-
supports():判断是否支持当前验证码类型,支持多种验证码类型共存的场景
-
verify():执行验证码校验逻辑,返回校验结果
自动注册机制
验证码认证的自动注册逻辑如下:
-
ThinkBridgeGlobalAuthenticationConfigurer 检测容器中是否存在 PasswordVerificationService Bean
-
如果存在,进一步检测 CaptchaVerificationService 类型的 Bean 列表
-
如果至少存在一个,自动注册 CaptchaAuthenticationProvider
-
整个流程受 think.auth.server.captcha.enable=true(默认启用)控制
通过 think.auth.server.captcha.close=true 可关闭验证码校验(仍启用验证码功能,但跳过校验步骤)。
实现示例
以下示例展示了如何实现自定义的验证码校验服务,只需校验 type 符合自己定义的 type 即可:
package com.thinkbridge.demo.auth.thinkbridge;
import com.luamas.thinkbridge.common.base.exception.*;
import com.luamas.thinkbridge.common.captcha.common.CaptchaManger;
import com.luamas.thinkbridge.common.captcha.common.dto.CaptchaVerificationDto;
import com.luamas.thinkbridge.common.security.authentication.captcha.CaptchaVerificationService;
import org.springframework.stereotype.Component;
import tools.jackson.databind.ObjectMapper;
@Component
public class CaptchaVerificationServiceImpl implements CaptchaVerificationService {
private final ObjectMapper objectMapper;
private final CaptchaManger captchaManger;
public CaptchaVerificationServiceImpl(ObjectMapper objectMapper, CaptchaManger captchaManger) {
this.objectMapper = objectMapper;
this.captchaManger = captchaManger;
}
/
* 检查
* @param captcha
* @return
*/
@Override
public boolean check(String captcha) {
try {
CaptchaVerificationDto<?, ?> dto = objectMapper.readValue(captcha, CaptchaVerificationDto.class);
captchaManger.verify(dto);
} catch (BusinessException e) {
throw UnauthorizedException.of(e.getCode(), e.getMessage(), e.getArgs());
} catch (Exception e) {
throw InternalException.of(BaseResultCode.INTERNAL_ERROR);
}
return true;
}
/
* 是否支持
* @param type
* @return
*/
@Override
public boolean supports(String type) {
return captchaManger.supports(type);
}
}
| 可以支持多种验证码类型(如图形验证码、滑动验证码、点击验证码等),在 supports() 方法中根据 type 进行匹配。 |
配置
授权服务器支持通过 think.auth.server.* 配置属性对认证流程进行精细化控制。
配置文件示例
以下为授权服务器的完整 application.yml 配置示例:
think:
auth:
server:
enabled: true # 启用授权服务器(默认 true)
init-client: false # 是否根据配置初始化客户端(默认 false)
captcha:
enable: true # 启用验证码(默认 true)
close: false # 关闭验证码校验(默认 false)
sms:
enable: true # 启用短信验证码登录(默认 true)
custom:
enable: true # 启用自定义认证(默认 true)
mini-program:
enable: true # 启用小程序登录(默认 true)
jwk-set:
json: '{"kty":"oct","kid":"my-key-id","k":"my-base64-encoded-key"}' # JWK 密钥配置(可选)
授权服务器配置
AuthorizationServerConfig
示例项目中的 AuthorizationServerConfig 配置类包含以下核心 Bean:
RegisteredClientRepository
自定义的 MyRegisteredClientRepository 实现,将 OAuth2 客户端配置持久化到数据库:
@Bean
public MyRegisteredClientRepository myRegisteredClientRepository(IOauth2ClientService iOauth2ClientService) {
MyRegisteredClientRepository myJdbcRegisteredClientRepository = new MyRegisteredClientRepository(iOauth2ClientService);
return myJdbcRegisteredClientRepository;
}
PasswordEncoder
密码编码器配置,支持多种密码编码格式:
@Bean
public PasswordEncoder passwordEncoder() {
DelegatingPasswordEncoder delegatingPasswordEncoder = (DelegatingPasswordEncoder) PasswordEncoderFactories.createDelegatingPasswordEncoder();
delegatingPasswordEncoder.setDefaultPasswordEncoderForMatches(NoOpPasswordEncoder.getInstance());
return delegatingPasswordEncoder;
}
OAuth2 端点
授权服务器注册以下标准 OAuth2 端点:
端点 |
说明 |
/oauth2/token |
Token 端点,用于获取和刷新 Token |
/oauth2/authorize |
授权端点,用于授权码流程 |
/oauth2/jwks |
JWK Set 端点,用于获取公钥 |
/oauth2/revoke |
Token 撤销端点 |
/oauth2/introspect |
Token 自省端点 |
.well-known/oauth-authorization-server |
OAuth2 元数据端点 |
.well-known/openid-configuration |
OIDC 配置端点 |
自动配置
AuthorizationServerAutoConfiguration 自动配置类默认启用( think.auth.server.enabled=true),包含以下核心功能:
ThinkBridgeOAuth2AuthorizationServerConfiguration
自定义 OAuth2 配置,包含以下扩展功能:
-
扩展授权类型:支持密码模式、验证码模式、短信登录、小程序登录等扩展授权类型
-
AuthenticationConverter:每种扩展授权类型对应一个请求转换器,从 HTTP 请求中提取认证参数
-
AuthenticationProvider:对应的认证处理器,验证认证参数并生成 Token
-
Token 端点:所有扩展授权类型共享 Token 端点,通过 grant_type 参数自动匹配对应的转换器和处理器
ThinkBridgeGlobalAuthenticationConfigurer
全局认证处理器配置,根据配置属性自动注册以下认证提供者:
-
PasswordAuthenticationProvider:用户名密码认证(始终启用)
-
CaptchaAuthenticationProvider:图形验证码认证(需启用 think.auth.server.captcha.enable)
-
SMSAuthenticationProvider:短信验证码认证(需启用 think.auth.server.sms.enable)
-
CustomAuthenticationProvider:自定义认证(需启用 think.auth.server.custom.enable)
-
MiniProgramAuthenticationProvider:小程序登录(需启用 think.auth.server.mini-program.enable)
以上认证提供者仅在对应的 Service Bean 存在时才会注册。
ThinkbridgeOAuth2TokenCustomizer
Token 自定义器,自动将 UserInfo 中 getExtend() 返回的扩展信息注入到 JWT 的 Claims 中。
Claims 的 key 格式为 {userinfoExtPrefix}{extendKey},前缀通过 think.auth.userinfo-ext-prefix 配置。
InitClientFromConfigToRepositoryRuner
启动时初始化客户端 Runner,需满足以下条件:
-
think.auth.server.init-client=true
-
存在 RegisteredClientRepository Bean
-
存在 InitAuthorizationService Bean
启动时会从配置文件中读取客户端配置,调用 RegisteredClientRepository.save() 方法将配置持久化到数据库。
完整的配置属性请参考 授权基础配置 文档。