跳到主要内容
Spring Security OAuth2 实战:从授权服务器到微服务网关 | 极客日志
Java java
Spring Security OAuth2 实战:从授权服务器到微服务网关 介绍 Spring Authorization Server 在 OAuth 2.1 和 OpenID Connect 标准下的应用。涵盖核心概念、授权模式详解、服务端搭建(含数据库存储)、客户端配置、资源服务器集成、单点登录(SSO)架构及微服务网关整合方案。提供版本选择建议、安全最佳实践、性能优化策略及常见问题解决方案,帮助开发者构建安全的认证授权体系。
观心 发布于 2026/3/23 更新于 2026/6/3 12K 浏览一、Spring Authorization Server 概述
1.1 什么是 Spring Authorization Server
Spring Authorization Server 是 Spring 官方推出的新一代认证授权框架,提供了 OAuth 2.1 和 OpenID Connect 1.0 规范的完整实现。它建立在 Spring Security 之上,为构建身份提供者和授权服务器提供了安全、轻量级且可定制的基础。
核心特性 :
完全支持 OAuth 2.1 和 OpenID Connect 1.0
模块化设计,易于扩展和定制
内置多种授权模式支持
与 Spring 生态系统无缝集成
官方资源 :
1.2 为什么需要 Spring Authorization Server
随着网络和设备的发展,原有的 OAuth 2.0 协议已无法满足现代应用的安全需求。OAuth 社区推出了 OAuth 2.1 协议,对原有授权模式进行了优化和调整:
移除了密码模式(password)和简化模式(implicit)
增加了设备授权码模式
为授权码模式增加了 PKCE 扩展
Spring Security 团队因此重新开发了 Spring Authorization Server,以替代原有的 Spring Security OAuth 2.0 项目。
二、OAuth 2.0 协议详解
2.1 OAuth 2.0 核心概念
四个关键角色 :
客户端(Client) :第三方应用,请求访问用户资源
资源服务器(Resource Server) :存储受保护资源的服务器
资源所有者(Resource Owner) :拥有资源的用户
授权服务器(Authorization Server) :验证用户身份并颁发令牌
2.2 OAuth 2.0 工作流程
令牌(Token)与密码(Password)的区别 :
令牌是短期的,到期自动失效
令牌可以被资源所有者随时撤销
令牌有权限范围(scope),密码拥有完整权限
2.3 OAuth 2.0 应用场景
社交媒体登录 :使用微信、QQ 等第三方账号登录
第三方应用集成 :应用间数据共享和 API 调用
移动应用访问 API :移动端应用访问后端服务
:访问 Google Drive、Dropbox 等云存储
云服务授权
IoT 设备访问 :物联网设备安全访问云服务
2.4 OAuth 2.0 授权模式
2.4.1 客户端模式(Client Credentials Grant) 适用于:服务端应用间的通信
流程:客户端直接使用 client_id 和 client_secret 获取令牌
POST /oauth2/token grant_type=client_credentials&client_id=CLIENT_ID&client_secret=CLIENT_SECRET
2.4.2 密码模式(Resource Owner Password Credentials Grant) 适用于:高度信任的内部应用
流程:用户提供用户名密码,客户端代理获取令牌
注意:OAuth 2.1 中已移除此模式
POST /oauth2/token grant_type=password&username=USERNAME&password=PASSWORD&client_id=CLIENT_ID&client_secret=CLIENT_SECRET
2.4.3 授权码模式(Authorization Code Grant) 适用于:Web 应用、移动应用
流程:通过授权码中间步骤,安全性最高
客户端引导用户到授权服务器
用户登录并授权
授权服务器返回授权码
客户端使用授权码交换令牌
GET /oauth2/authorize?response_type=code&client_id=CLIENT_ID&redirect_uri=CALLBACK_URL&scope=read
POST /oauth2/token grant_type=authorization_code&code=AUTHORIZATION_CODE&client_id=CLIENT_ID&client_secret=CLIENT_SECRET&redirect_uri=CALLBACK_URL
2.4.4 简化模式(Implicit Grant) 适用于:单页应用(SPA)
流程:直接返回令牌,跳过授权码步骤
注意:OAuth 2.1 中已移除此模式
2.4.5 刷新令牌模式(Refresh Token Grant) 适用于:令牌续期
流程:使用 refresh_token 获取新的 access_token
POST /oauth2/token grant_type=refresh_token&client_id=CLIENT_ID&client_secret=CLIENT_SECRET&refresh_token=REFRESH_TOKEN
三、OAuth 2.1 协议新特性
3.1 授权码模式+PKCE 扩展 PKCE(Proof Key for Code Exchange)用于防止授权码被拦截攻击:
客户端生成 code_verifier 和 code_challenge
授权请求时发送 code_challenge
交换令牌时发送 code_verifier
服务器验证两者匹配关系
3.2 设备授权码模式
设备请求设备码和用户码
用户在另一设备访问验证页面输入用户码
设备轮询获取令牌
3.3 拓展授权模式 虽然 OAuth 2.1 移除了密码模式,但可通过拓展授权模式实现类似功能。
四、OpenID Connect 1.0 协议 OpenID Connect 是建立在 OAuth 2.0 之上的身份层,主要增加了 id_token:
基于 JWT 格式的 id_token
用户信息端点(UserInfo Endpoint)
标准化声明(Claims)
{
"iss" : "https://server.example.com" ,
"sub" : "24400320" ,
"aud" : "s6BhdRkqt3" ,
"exp" : 1311281970 ,
"iat" : 1311280970 ,
"auth_time" : 1311280969 ,
"nonce" : "n-0S6_WzA2Mj"
}
五、Spring Authorization Server 实战
5.1 授权服务器搭建
5.1.1 项目依赖 <dependency >
<groupId > org.springframework.boot</groupId >
<artifactId > spring-boot-starter-oauth2-authorization-server</artifactId >
</dependency >
5.1.2 核心配置类 @Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
@Order(1)
public SecurityFilterChain authorizationServerSecurityFilterChain (HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
http
.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
.oidc(Customizer.withDefaults());
return http.build();
}
@Bean
@Order(2)
public SecurityFilterChain defaultSecurityFilterChain (HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorize -> authorize.anyRequest().authenticated())
.formLogin(Customizer.withDefaults());
return http.build();
}
@Bean
public UserDetailsService userDetailsService () {
UserDetails userDetails = User.withDefaultPasswordEncoder()
.username("fox" )
.password("123456" )
.roles("USER" )
.build();
return new InMemoryUserDetailsManager (userDetails);
}
@Bean
public RegisteredClientRepository registeredClientRepository () {
RegisteredClient oidcClient = RegisteredClient.withId(UUID.randomUUID().toString())
.clientId("oidc-client" )
.clientSecret("{noop}secret" )
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
.redirectUri("http://www.baidu.com" )
.scope(OidcScopes.OPENID)
.scope(OidcScopes.PROFILE)
.clientSettings(ClientSettings.builder().requireAuthorizationConsent(true ).build())
.build();
return new InMemoryRegisteredClientRepository (oidcClient);
}
@Bean
public JWKSource<SecurityContext> jwkSource () {
KeyPair keyPair = generateRsaKey();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
RSAKey rsaKey = new RSAKey .Builder(publicKey)
.privateKey(privateKey)
.keyID(UUID.randomUUID().toString())
.build();
JWKSet jwkSet = new JWKSet (rsaKey);
return new ImmutableJWKSet <>(jwkSet);
}
private static KeyPair generateRsaKey () {
KeyPair keyPair;
try {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA" );
keyPairGenerator.initialize(2048 );
keyPair = keyPairGenerator.generateKeyPair();
} catch (Exception ex) {
throw new IllegalArgumentException (ex);
}
return keyPair;
}
}
5.1.3 测试端点 GET http://127.0.0.1:9000/.well-known/openid-configuration
GET http://localhost:9000/oauth2/authorize?response_type=code&client_id=oidc-client&scope=profile+openid&redirect_uri=http://www.baidu.com
curl -X POST http://localhost:9000/oauth2/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-u "oidc-client:secret" \
-d "grant_type=authorization_code" \
-d "code={授权码}" \
-d "redirect_uri=http://www.baidu.com"
5.2 OAuth2 客户端搭建
5.2.1 项目依赖 <dependency >
<groupId > org.springframework.boot</groupId >
<artifactId > spring-boot-starter-oauth2-client</artifactId >
</dependency >
<dependency >
<groupId > org.springframework.boot</groupId >
<artifactId > spring-boot-starter-web</artifactId >
</dependency >
5.2.2 配置文件 server:
port: 9001
spring:
application:
name: spring-oauth-client
security:
oauth2:
client:
provider:
oauth-server:
issuer-uri: http://spring-oauth-server:9000
authorization-uri: http://spring-oauth-server:9000/oauth2/authorize
token-uri: http://spring-oauth-server:9000/oauth2/token
registration:
messaging-client-oidc:
provider: oauth-server
client-name: web 平台
client-id: web-client-id
client-secret: secret
client-authentication-method: client_secret_basic
authorization-grant-type: authorization_code
redirect-uri: http://spring-oauth-client:9001/login/oauth2/code/messaging-client-oidc
scope:
- profile
- openid
127.0.0.1 spring-oauth-client
127.0.0.1 spring-oauth-server
5.2.3 客户端控制器 @RestController
public class AuthenticationController {
@GetMapping("/token")
@ResponseBody
public OAuth2AuthorizedClient token (@RegisteredOAuth2AuthorizedClient OAuth2AuthorizedClient oAuth2AuthorizedClient) {
return oAuth2AuthorizedClient;
}
}
5.3 资源服务器搭建
5.3.1 项目依赖 <dependency >
<groupId > org.springframework.boot</groupId >
<artifactId > spring-boot-starter-oauth2-resource-server</artifactId >
</dependency >
<dependency >
<groupId > org.springframework.boot</groupId >
<artifactId > spring-boot-starter-web</artifactId >
</dependency >
5.3.2 配置文件 server:
port: 9002
spring:
application:
name: spring-oauth-resource
security:
oauth2:
resource-server:
jwt:
issuer-uri: http://spring-oauth-server:9000
5.3.3 安全配置 @Configuration
@EnableWebSecurity
@EnableMethodSecurity(jsr250Enabled = true, securedEnabled = true)
public class ResourceServerConfig {
@Bean
SecurityFilterChain securityFilterChain (HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorize -> authorize.anyRequest().authenticated())
.oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()));
return http.build();
}
}
5.3.4 资源接口 @RestController
public class MessagesController {
@GetMapping("/messages1")
public String getMessages1 () {
return "hello Message 1" ;
}
@GetMapping("/messages2")
@PreAuthorize("hasAuthority('SCOPE_profile')")
public String getMessages2 () {
return "hello Message 2" ;
}
@GetMapping("/messages3")
@PreAuthorize("hasAuthority('SCOPE_Message')")
public String getMessages3 () {
return "hello Message 3" ;
}
}
5.3.5 自定义异常处理
@Component
public class MyAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence (HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
if (authException instanceof InvalidBearerTokenException) {
ResponseResult.exceptionResponse(response, "令牌无效或已过期" );
} else {
ResponseResult.exceptionResponse(response, "需要带上令牌进行访问" );
}
}
}
@Component
public class MyAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle (HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException {
ResponseResult.exceptionResponse(response, "权限不足" );
}
}
http.oauth2ResourceServer(resourceServer -> resourceServer
.jwt(Customizer.withDefaults())
.authenticationEntryPoint(new MyAuthenticationEntryPoint ())
.accessDeniedHandler(new MyAccessDeniedHandler ()));
六、基于数据库存储改造
6.1 数据库表结构
6.1.1 客户端信息表 CREATE TABLE oauth2_registered_client (
id VARCHAR (100 ) NOT NULL ,
client_id VARCHAR (100 ) NOT NULL ,
client_id_issued_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL ,
client_secret VARCHAR (200 ) DEFAULT NULL ,
client_secret_expires_at TIMESTAMP DEFAULT NULL ,
client_name VARCHAR (200 ) NOT NULL ,
client_authentication_methods VARCHAR (1000 ) NOT NULL ,
authorization_grant_types VARCHAR (1000 ) NOT NULL ,
redirect_uris VARCHAR (1000 ) DEFAULT NULL ,
post_logout_redirect_uris VARCHAR (1000 ) DEFAULT NULL ,
scopes VARCHAR (1000 ) NOT NULL ,
client_settings VARCHAR (2000 ) NOT NULL ,
token_settings VARCHAR (2000 ) NOT NULL ,
PRIMARY KEY (id)
);
6.1.2 授权确认表 CREATE TABLE oauth2_authorization_consent (
registered_client_id VARCHAR (100 ) NOT NULL ,
principal_name VARCHAR (200 ) NOT NULL ,
authorities VARCHAR (1000 ) NOT NULL ,
PRIMARY KEY (registered_client_id, principal_name)
);
6.1.3 授权信息表 CREATE TABLE oauth2_authorization (
id VARCHAR (100 ) NOT NULL ,
registered_client_id VARCHAR (100 ) NOT NULL ,
principal_name VARCHAR (200 ) NOT NULL ,
authorization_grant_type VARCHAR (100 ) NOT NULL ,
authorized_scopes VARCHAR (1000 ) DEFAULT NULL ,
attributes BLOB DEFAULT NULL ,
state VARCHAR (500 ) DEFAULT NULL ,
authorization_code_value BLOB DEFAULT NULL ,
authorization_code_issued_at TIMESTAMP DEFAULT NULL ,
authorization_code_expires_at TIMESTAMP DEFAULT NULL ,
authorization_code_metadata BLOB DEFAULT NULL ,
access_token_value BLOB DEFAULT NULL ,
access_token_issued_at TIMESTAMP DEFAULT NULL ,
access_token_expires_at TIMESTAMP DEFAULT NULL ,
access_token_metadata BLOB DEFAULT NULL ,
access_token_type VARCHAR (100 ) DEFAULT NULL ,
access_token_scopes VARCHAR (1000 ) DEFAULT NULL ,
oidc_id_token_value BLOB DEFAULT NULL ,
oidc_id_token_issued_at TIMESTAMP DEFAULT NULL ,
oidc_id_token_expires_at TIMESTAMP DEFAULT NULL ,
oidc_id_token_metadata BLOB DEFAULT NULL ,
refresh_token_value BLOB DEFAULT NULL ,
refresh_token_issued_at TIMESTAMP DEFAULT NULL ,
refresh_token_expires_at TIMESTAMP DEFAULT NULL ,
refresh_token_metadata BLOB DEFAULT NULL ,
user_code_value BLOB DEFAULT NULL ,
user_code_issued_at TIMESTAMP DEFAULT NULL ,
user_code_expires_at TIMESTAMP DEFAULT NULL ,
user_code_metadata BLOB DEFAULT NULL ,
device_code_value BLOB DEFAULT NULL ,
device_code_issued_at TIMESTAMP DEFAULT NULL ,
device_code_expires_at TIMESTAMP DEFAULT NULL ,
device_code_metadata BLOB DEFAULT NULL ,
PRIMARY KEY (id)
);
6.1.4 用户表 CREATE TABLE sys_user (
id BIGINT NOT NULL AUTO_INCREMENT COMMENT 'id' ,
username VARCHAR (20 ) NOT NULL DEFAULT '' COMMENT '用户名' ,
password VARCHAR (255 ) NOT NULL DEFAULT '' COMMENT '密码' ,
name VARCHAR (50 ) DEFAULT NULL COMMENT '姓名' ,
description VARCHAR (255 ) DEFAULT NULL COMMENT '描述' ,
status TINYINT DEFAULT NULL COMMENT '状态(1:正常 0:停用)' ,
PRIMARY KEY (id),
UNIQUE KEY idx_username (username)
) ENGINE= InnoDB DEFAULT CHARSET= utf8mb4 COMMENT= '用户表' ;
6.2 数据库配置
6.2.1 配置文件 spring:
application:
name: spring-oauth-server
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/oauth-server?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
username: root
password: root
6.2.2 数据库服务配置 @Configuration
public class DatabaseConfig {
@Bean
public RegisteredClientRepository registeredClientRepository (JdbcTemplate jdbcTemplate) {
return new JdbcRegisteredClientRepository (jdbcTemplate);
}
@Bean
public OAuth2AuthorizationService authorizationService (JdbcTemplate jdbcTemplate, RegisteredClientRepository registeredClientRepository) {
return new JdbcOAuth2AuthorizationService (jdbcTemplate, registeredClientRepository);
}
@Bean
public OAuth2AuthorizationConsentService authorizationConsentService (JdbcTemplate jdbcTemplate, RegisteredClientRepository registeredClientRepository) {
return new JdbcOAuth2AuthorizationConsentService (jdbcTemplate, registeredClientRepository);
}
@Bean
public PasswordEncoder passwordEncoder () {
return new BCryptPasswordEncoder ();
}
}
6.2.3 自定义用户详情服务 @Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Resource
private SysUserService sysUserService;
@Override
public UserDetails loadUserByUsername (String username) throws UsernameNotFoundException {
SysUserEntity sysUserEntity = sysUserService.selectByUsername(username);
List<SimpleGrantedAuthority> authorities = Arrays.asList("USER" ).stream()
.map(SimpleGrantedAuthority::new )
.collect(Collectors.toList());
return new User (username, sysUserEntity.getPassword(), authorities);
}
}
七、单点登录(SSO)实战
7.1 SSO 架构设计 ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ 订单服务 │ │ 商品服务 │ │ 认证服务器 │
│ (客户端) │ │ (客户端) │ │ (授权服务器)│
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘
│ │ │
└───────────────┼───────────────┘
│
┌──────┴──────┐
│ 用户 │
│ (浏览器) │
└─────────────┘
7.2 订单服务配置 server:
ip: spring-oauth-client-order
port: 9003
spring:
application:
name: spring-oauth-client-order
security:
oauth2:
client:
provider:
oauth-server:
issuer-uri: http://spring-oauth-server:9000
authorization-uri: http://spring-oauth-server:9000/oauth2/authorize
token-uri: http://spring-oauth-server:9000/oauth2/token
registration:
messaging-client-oidc:
provider: oauth-server
client-name: web 平台-SSO 客户端 - 订单服务
client-id: web-client-id-order
client-secret: secret
client-authentication-method: client_secret_basic
authorization-grant-type: authorization_code
redirect-uri: http://spring-oauth-client-order:9003/login/oauth2/code/messaging-client-oidc
scope:
- profile
- openid
7.3 商品服务配置 server:
ip: spring-oauth-client-product
port: 9004
spring:
application:
name: spring-oauth-client-product
security:
oauth2:
client:
provider:
oauth-server:
issuer-uri: http://spring-oauth-server:9000
authorization-uri: http://spring-oauth-server:9000/oauth2/authorize
token-uri: http://spring-oauth-server:9000/oauth2/token
registration:
messaging-client-oidc:
provider: oauth-server
client-name: web 平台-SSO 客户端 - 商品服务
client-id: web-client-id-product
client-secret: secret
client-authentication-method: client_secret_basic
authorization-grant-type: authorization_code
redirect-uri: http://spring-oauth-client-product:9004/login/oauth2/code/messaging-client-oidc
scope:
- profile
- openid
7.4 SSO 测试流程
首次访问订单服务 :跳转到认证服务器登录
登录成功后 :返回订单服务页面
跳转到商品服务 :无需重新登录,直接访问
无感授权配置 :设置 require-authorization-consent=false 跳过授权确认
八、微服务网关整合 OAuth2
8.1 网关安全架构 ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ 用户 │───▶│ 网关 │───▶│ 认证服务器│
│ (浏览器) │ │ (Gateway) │ │ (OAuth2) │
└─────────────┘ └──────┬──────┘ └─────────────┘
│
┌──────┴──────┐
│ 资源服务 │
│ (微服务) │
└─────────────┘
8.2 网关配置
8.2.1 项目依赖
<dependency >
<groupId > org.springframework.boot</groupId >
<artifactId > spring-boot-starter-oauth2-client</artifactId >
<version > 3.1.4</version >
</dependency >
<dependency >
<groupId > org.springframework.boot</groupId >
<artifactId > spring-boot-starter-oauth2-resource-server</artifactId >
<version > 3.1.4</version >
</dependency >
8.2.2 配置文件 server:
port: 8888
spring:
application:
name: mall-gateway
security:
oauth2:
resourceserver:
jwt:
issuer-uri: http://spring-oauth-server:9000
client:
provider:
oauth-server:
issuer-uri: http://spring-oauth-server:9000
authorization-uri: http://spring-oauth-server:9000/oauth2/authorize
token-uri: http://spring-oauth-server:9000/oauth2/token
registration:
messaging-client-oidc:
provider: oauth-server
client-name: 网关服务
client-id: mall-gateway-id
client-secret: secret
client-authentication-method: client_secret_basic
authorization-grant-type: authorization_code
redirect-uri: http://mall-gateway:8888/login/oauth2/code/messaging-client-oidc
scope:
- profile
- openid
cloud:
gateway:
default-filters:
- TokenRelay=
8.2.3 安全配置 @Configuration
@EnableWebFluxSecurity
@EnableReactiveMethodSecurity
public class WebSecurityConfig {
@Bean
public SecurityWebFilterChain defaultSecurityFilterChain (ServerHttpSecurity http) {
http.authorizeExchange(authorize -> authorize.anyExchange().authenticated());
http.oauth2Login(Customizer.withDefaults());
http.oauth2ResourceServer(resourceServer -> resourceServer.jwt(Customizer.withDefaults()));
http.csrf(csrf -> csrf.disable());
http.cors(cors -> cors.disable());
return http.build();
}
}
8.3 微服务资源服务器配置
8.3.1 项目依赖 <dependency >
<groupId > org.springframework.boot</groupId >
<artifactId > spring-boot-starter-oauth2-resource-server</artifactId >
<version > 3.1.4</version >
</dependency >
8.3.2 配置文件 spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: http://spring-oauth-server:9000
8.3.3 安全配置 @Configuration
@EnableWebSecurity
@EnableMethodSecurity(jsr250Enabled = true, securedEnabled = true)
public class ResourceServerConfig {
@Bean
SecurityFilterChain securityFilterChain (HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorize -> authorize.anyRequest().authenticated())
.oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()));
return http.build();
}
}
8.3.4 Feign 拦截器(令牌传递) @Slf4j
@Component
public class FeignAuthRequestInterceptor implements RequestInterceptor {
@Override
public void apply (RequestTemplate template) {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attributes != null ) {
HttpServletRequest request = attributes.getRequest();
String accessToken = request.getHeader("Authorization" );
log.info("从 Request 中解析请求头:{}" , accessToken);
template.header("Authorization" , accessToken);
}
}
}
8.4 测试流程
访问网关受保护接口 :http://mall-gateway:8888/user/findOrderByUserId/1
网关检测未认证 :重定向到认证服务器登录页面
用户登录授权 :输入用户名密码,确认授权
返回网关页面 :携带 token,正常访问资源
网关转发请求 :自动传递 token 到下游微服务
微服务验证 token :验证通过,返回数据
九、总结与最佳实践
9.1 版本选择建议 组件 推荐版本 说明 Spring Boot 3.1.4+ 支持 Spring Authorization Server 最新特性 Spring Authorization Server 1.1.2+ 稳定版本,功能完整 JDK 17+ Spring Boot 3.x 要求 MySQL 8.0+ 支持 JSON 字段,性能更好
9.2 安全建议
令牌管理 :
Access Token 有效期建议设置为 30 分钟
Refresh Token 有效期建议设置为 7 天
使用 HTTPS 传输令牌
客户端安全 :
使用 BCrypt 加密存储 client_secret
定期轮换客户端密钥
限制客户端 IP 白名单
权限控制 :
最小权限原则,按需分配 scope
使用@PreAuthorize 注解进行方法级权限控制
记录敏感操作日志
9.3 性能优化
缓存策略 :
缓存 JWK 公钥,减少网络请求
使用 Redis 缓存用户信息
数据库连接池优化
数据库优化 :
为 oauth2_authorization 表添加索引
定期清理过期令牌记录
使用读写分离架构
9.4 监控与告警
9.5 扩展功能
多因素认证 :集成短信、邮箱验证码
社交登录 :集成微信、QQ 等第三方登录
设备管理 :管理已授权设备,支持一键下线
审计日志 :完整记录认证授权操作日志
十、常见问题解决
10.1 跨域问题 @Bean
public CorsConfigurationSource corsConfigurationSource () {
CorsConfiguration configuration = new CorsConfiguration ();
configuration.setAllowedOrigins(Arrays.asList("http://localhost:8080" ));
configuration.setAllowedMethods(Arrays.asList("GET" , "POST" , "PUT" , "DELETE" ));
configuration.setAllowedHeaders(Arrays.asList("Authorization" , "Content-Type" ));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource ();
source.registerCorsConfiguration("/**" , configuration);
return source;
}
10.2 会话管理 spring:
session:
store-type: redis
redis:
namespace: spring:session
10.3 令牌刷新 @Component
public class TokenRefreshService {
@Scheduled(fixedDelay = 5 * 60 * 1000)
public void refreshTokens () {
}
}
本文基于 Spring Authorization Server 1.1.2 和 Spring Boot 3.1.4 编写,涵盖了从基础概念到生产级部署的全流程。在实际项目中,建议根据具体业务需求和安全要求进行调整和优化。
相关免费在线工具 Keycode 信息 查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
Escape 与 Native 编解码 JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
JavaScript / HTML 格式化 使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
JavaScript 压缩与混淆 Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online