当前位置: 首页 > news >正文

Spring Cloud Gateway + OAuth2 + JWT 单点登录(SSO)实现方案

一、概述

基于Spring Cloud微服务架构,通过Gateway网关、OAuth2协议和JWT令牌实现分布式系统的单点登录,允许用户一次登录后访问所有互信的微服务。核心技术组件包括:

  • Spring Cloud Gateway:统一请求入口,负责路由、Token验证和转发
  • OAuth2协议:定义授权流程,实现用户认证和授权码交换
  • JWT(Json Web Token):作为无状态令牌载体,包含用户身份和权限信息
二、系统架构与服务组件
1. 服务架构图
+----------------+     +----------------+     +----------------+
|                |     |                |     |                |
|  客户端应用     |<--->|   API网关      |<--->|  认证中心      |
|  (sso-client)   |     |  (api-gateway) |     | (sso-auth-server)|
|                |     |                |     |                |
+----------------+     +--------+-------+     +--------+-------+|v
+----------------+     +----------------+
|                |     |                |
|  用户服务       |     |  订单服务      |
| (user-service)  |     |(order-service)|
|                |     |                |
+----------------+     +----------------+
2. 服务职责说明
服务名称职责描述
认证中心处理用户登录、生成JWT令牌、管理客户端注册信息,作为OAuth2授权服务器
API网关统一请求入口,实现路由分发、Token验证与传递,集成OAuth2客户端配置
资源服务提供业务数据接口(如用户、订单服务),验证Token并基于权限控制访问
客户端应用用户交互入口,引导登录、获取Token并调用资源服务,展示业务数据
三、核心技术实现
1. 认证中心(auth-server)配置
<!-- 认证中心依赖配置(pom.xml) -->
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-oauth2</artifactId></dependency><dependency><groupId>org.springframework.security</groupId><artifactId>spring-security-oauth2-jose</artifactId></dependency>
</dependencies>
// 认证服务器核心配置(AuthorizationServerConfig.java)
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {@Autowired private AuthenticationManager authenticationManager;@Autowired private UserDetailsService userDetailsService;@Autowired private TokenStore tokenStore;@Autowired private JwtAccessTokenConverter accessTokenConverter;@Overridepublic void configure(ClientDetailsServiceConfigurer clients) throws Exception {clients.inMemory().withClient("sso-client").secret("{noop}sso-secret").authorizedGrantTypes("authorization_code", "refresh_token", "password").scopes("read", "write", "profile").redirectUris("http://localhost:8081/login/oauth2/code/custom").accessTokenValiditySeconds(3600).refreshTokenValiditySeconds(86400);}@Overridepublic void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {endpoints.authenticationManager(authenticationManager).userDetailsService(userDetailsService).tokenStore(tokenStore).accessTokenConverter(accessTokenConverter).allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST);}
}
// Spring Security配置(SecurityConfig.java)
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Bean@Overridepublic UserDetailsService userDetailsServiceBean() throws Exception {InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();manager.createUser(User.withUsername("user").password("{noop}password").roles("USER").authorities("READ", "WRITE").build());return manager;}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.csrf().disable().authorizeRequests().antMatchers("/oauth/authorize", "/login").permitAll().anyRequest().authenticated().and().formLogin().permitAll();}@Beanpublic TokenStore tokenStore() {return new JwtTokenStore(accessTokenConverter());}@Beanpublic JwtAccessTokenConverter accessTokenConverter() {JwtAccessTokenConverter converter = new JwtAccessTokenConverter();converter.setSigningKey("sso-jwt-secret-key");return converter;}
}
# 认证中心配置文件(application.yml)
server:port: 8080spring:application:name: sso-auth-serversecurity:oauth2:resourceserver:jwt:issuer-uri: http://localhost:8080/
2. 网关服务(gateway)配置
<!-- 网关依赖配置(pom.xml) -->
<dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-oauth2-client</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId></dependency>
</dependencies>
# 网关核心配置(application.yml)
server:port: 8081spring:application:name: sso-gatewaycloud:gateway:routes:- id: user-serviceuri: lb://USER-SERVICEpredicates: Path=/user/**filters: [TokenRelay, RewritePath=/user/(?<segment>.*), /$\{segment}]- id: resource-serviceuri: lb://RESOURCE-SERVICEpredicates: Path=/resource/**filters: [TokenRelay, RewritePath=/resource/(?<segment>.*), /$\{segment}]globalcors:cors-configurations:'[/**]':allowed-origins: "*"allowed-methods: GET, POST, PUT, DELETEsecurity:oauth2:client:provider:custom:authorization-uri: http://localhost:8080/oauth/authorizetoken-uri: http://localhost:8080/oauth/tokenregistration:custom:client-id: sso-clientclient-secret: sso-secretauthorization-grant-type: authorization_coderedirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"
// 网关安全配置(GatewaySecurityConfig.java)
@Configuration
@EnableWebFluxSecurity
public class GatewaySecurityConfig {@Beanpublic SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {http.authorizeExchange(exchanges -> exchanges.pathMatchers("/login/**", "/oauth2/**").permitAll().anyExchange().authenticated()).oauth2Login().and().oauth2ResourceServer().jwt();return http.build();}
}
3. 资源服务(user-service)配置
// 资源服务器安全配置(ResourceServerConfig.java)
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http.csrf().disable().authorizeRequests().antMatchers("/public/**").permitAll().antMatchers("/user/info").hasAnyRole("USER").antMatchers("/user/admin").hasRole("ADMIN").anyRequest().authenticated().and().oauth2ResourceServer().jwt();}
}
// 资源接口示例(UserController.java)
@RestController
@RequestMapping("/user")
public class UserController {@GetMapping("/info")public Map<String, Object> getUserInfo(Principal principal) {Map<String, Object> result = new HashMap<>();result.put("username", principal.getName());result.put("timestamp", System.currentTimeMillis());result.put("message", "访问用户信息接口成功");return result;}@GetMapping("/admin")public String adminOnly() {return "这是管理员专用接口,只有ADMIN角色可访问";}
}
# 资源服务配置文件(application.yml)
server:port: 8082spring:application:name: user-servicesecurity:oauth2:resourceserver:jwt:issuer-uri: http://localhost:8080/
4. 客户端应用(client)配置
// 客户端登录控制器(SsoController.java)
@Controller
public class SsoController {@Autowired private RestTemplate restTemplate;@GetMapping("/login")public void login(HttpServletResponse response) throws IOException {String authUrl = "http://localhost:8080/oauth/authorize" +"?response_type=code&client_id=sso-client" +"&redirect_uri=http://localhost:8081/login/oauth2/code/custom";response.sendRedirect(authUrl);}@GetMapping("/callback")public String callback(@RequestParam("code") String code, Model model) {String tokenUri = "http://localhost:8080/oauth/token";HttpHeaders headers = new HttpHeaders();headers.setBasicAuth("sso-client", "sso-secret");MultiValueMap<String, String> params = new LinkedMultiValueMap<>();params.add("grant_type", "authorization_code");params.add("code", code);params.add("redirect_uri", "http://localhost:8081/login/oauth2/code/custom");ResponseEntity<Map> response = restTemplate.exchange(tokenUri, HttpMethod.POST, new HttpEntity<>(params, headers), Map.class);String accessToken = (String) response.getBody().get("access_token");model.addAttribute("accessToken", accessToken);return "home";}
}
# 客户端配置文件(application.yml)
server:port: 8083spring:application:name: sso-clientsecurity:oauth2:client:provider:custom:authorization-uri: http://localhost:8080/oauth/authorizetoken-uri: http://localhost:8080/oauth/tokenregistration:custom:client-id: sso-clientclient-secret: sso-secretauthorization-grant-type: authorization_coderedirect-uri: "http://localhost:8081/login/oauth2/code/custom"
5.项目结构图
5.1 项目结构图
sso-example/
├── auth-server/         # 认证中心服务
│   ├── src/
│   │   ├── main/
│   │   │   ├── java/
│   │   │   │   └── com/example/authserver/
│   │   │   │       ├── AuthServerApplication.java    # 主启动类
│   │   │   │       ├── config/                      # 配置类目录
│   │   │   │       │   ├── AuthorizationServerConfig.java  # OAuth2认证服务器配置
│   │   │   │       │   ├── SecurityConfig.java       # Spring Security配置
│   │   │   │       │   └── JwtConfig.java            # JWT配置
│   │   │   │       └── entity/                      # 实体类目录
│   │   │   │           └── User.java                 # 用户实体
│   │   │   └── resources/
│   │   │       ├── application.yml                   # 应用配置文件
│   │   │       └── static/
│   │   │           └── login.html                    # 登录页面
│   │   └── test/
│   └── pom.xml                                      # 模块依赖配置
│
├── api-gateway/         # 网关服务
│   ├── src/
│   │   ├── main/
│   │   │   ├── java/
│   │   │   │   └── com/example/gateway/
│   │   │   │       ├── GatewayApplication.java       # 主启动类
│   │   │   │       └── config/
│   │   │   │           └── GatewaySecurityConfig.java # 网关安全配置
│   │   │   └── resources/
│   │   │       └── application.yml                   # 应用配置文件
│   │   └── test/
│   └── pom.xml
│
├── user-service/        # 用户资源服务
│   ├── src/
│   │   ├── main/
│   │   │   ├── java/
│   │   │   │   └── com/example/userservice/
│   │   │   │       ├── UserServiceApplication.java   # 主启动类
│   │   │   │       ├── config/
│   │   │   │       │   └── ResourceServerConfig.java # 资源服务器安全配置
│   │   │   │       └── controller/
│   │   │   │           └── UserController.java       # 用户接口控制器
│   │   │   └── resources/
│   │   │       └── application.yml                   # 应用配置文件
│   │   └── test/
│   └── pom.xml
│
├── sso-client/          # 客户端应用
│   ├── src/
│   │   ├── main/
│   │   │   ├── java/
│   │   │   │   └── com/example/client/
│   │   │   │       ├── ClientApplication.java        # 主启动类
│   │   │   │       └── controller/
│   │   │   │           └── SsoController.java        # 单点登录控制器
│   │   │   └── resources/
│   │   │       ├── application.yml                   # 应用配置文件
│   │   │       ├── templates/
│   │   │       │   ├── home.html                     # 首页
│   │   │       │   └── resource.html                 # 资源页面
│   │   └── test/
│   └── pom.xml
│
└── pom.xml              # 父项目依赖配置
5.2 核心模块功能说明
模块名称功能定位关键组件
auth-server认证中心,负责用户登录、Token生成和OAuth2授权管理- AuthorizationServerConfig:OAuth2服务器配置
- SecurityConfig:用户认证配置
- JwtConfig:JWT签名配置
api-gateway统一网关,负责请求路由、Token验证和转发- GatewaySecurityConfig:网关安全配置
- application.yml:路由规则和OAuth2客户端配置
user-service资源服务示例,提供用户相关接口,需验证Token才能访问- ResourceServerConfig:资源服务器安全配置
- UserController:用户信息接口
sso-client客户端应用,处理用户交互、登录流程和资源访问请求- SsoController:登录、回调和资源访问逻辑
- application.yml:OAuth2客户端配置
5.3 模块依赖关系
提供认证服务
路由请求
重定向登录
调用资源
传递Token
auth-server
api-gateway
user-service
sso-client
四、用户登录流程详解
  1. 访问客户端应用:用户访问sso-client,未认证时重定向到认证中心
  2. 认证中心登录:输入user/password,认证中心生成授权码并回调客户端
  3. 换取访问令牌:客户端用授权码向认证中心请求AccessToken
  4. 资源访问:携带Token访问user-service,网关和资源服务验证Token有效性
  5. Token刷新:过期前通过RefreshToken获取新令牌,避免重复登录
用户访问客户端
已认证?
重定向到认证中心
用户登录
认证中心返回授权码
客户端换取AccessToken
携带Token访问资源
Token有效?
资源服务返回数据
五、部署与集成要点
  1. 服务启动顺序:认证中心→网关→资源服务→客户端应用
  2. 跨域配置:在网关和各服务中添加allowed-origins等CORS规则
  3. 生产环境优化
    • 用数据库存储客户端和用户信息,替代内存存储
    • 配置HTTPS保障通信安全,避免Token明文传输
    • 实现分布式会话管理,支持集群部署
六、方案优势与适用场景
1. 核心优势
  • 统一认证入口:一次登录访问所有微服务,提升用户体验
  • 无状态认证:基于JWT实现无状态会话,避免分布式会话共享问题
  • 细粒度权限控制:通过@PreAuthorize和角色/作用域限制接口访问
2. 适用场景
  • 分布式微服务架构的企业级应用
  • 多系统统一登录的平台(如中台系统)

相关文章:

  • Python 实现一个带进度条的 URL 批量下载工具(含 GUI 界面)
  • SKE 与 SM2、SM3、SM4 的关系 ,SPDM协议的详细解析
  • 伊吖学C笔记(6、数、求和、排列)
  • 亚远景-ASPICE认证流程全解析:从准备到通过的关键步骤
  • 从数学到代码:一文详解埃拉托色尼筛法(埃式筛)
  • 远程管理命令:网卡和IP地址的概念
  • SLAM文献之-Degeneracy-Aware Factors with Applications to Underwater SLAM
  • 解决office各种疑难杂症
  • Vue3+TypeScript实现状态模式
  • 力扣100- 环形链表
  • oracle 23ai对象注释新特性ANNOTATIONS
  • HALCON第六讲->测量和检测
  • 图书管理系统的功能与性能测试
  • COHERENT Chameleon™Ultra、Vision和Vision-S激光系统操作员手侧
  • 【hadoop】实时计算词频案例
  • [原创]X86C++反汇编03.除法的优化
  • Linux启动流程和内核管理自我总结
  • 在线机考|2025年华为暑期实习春招秋招编程题(最新)——第2题_网络整改
  • Mysql可以做分布式锁吗?Mysql分布式锁的应用
  • 图像处理控件Aspose.Imaging教程:用Java将 CMX 转换为 PNG
  • 网站推广策划公司/互联网营销师考试内容
  • 网站像素大小/深圳网络提速优化服务包
  • 衡水网站制作报价/seo自动优化软件
  • 郑州的做网站公司哪家好/云seo关键词排名优化软件
  • 个人建站的app哪里有卖/外链系统
  • 做设计英文网站/如何联系百度人工客服电话