若依框架中实现单点登录(SSO)方案

2025-06发布11次浏览

若依框架是一个基于Spring Boot和Spring Cloud的快速开发平台,它提供了许多开箱即用的功能模块,如权限管理、日志记录等。在企业级应用中,单点登录(SSO,Single Sign-On)是常见的需求之一,它允许用户在一个系统中登录后,无需再次登录即可访问其他相关系统。

下面我们将详细介绍如何在若依框架中实现单点登录方案。


一、单点登录的基本原理

单点登录的核心思想是通过一个统一的身份认证中心(Authentication Server),所有子系统都依赖该认证中心进行用户身份验证。当用户首次登录时,认证中心会生成一个凭证(Token或Cookie),并将其存储在浏览器中。后续访问其他子系统时,子系统会将凭证发送给认证中心验证,如果凭证有效,则允许访问资源。

常见的SSO实现方式有以下几种:

  1. 基于Cookie:通过共享域名下的Cookie实现。
  2. 基于Token:通过OAuth2或JWT等协议实现。
  3. 基于CAS(Central Authentication Service):使用第三方中间件实现。
  4. 基于SAML:适用于跨组织间的SSO。

在若依框架中,我们推荐结合OAuth2和JWT技术实现SSO。


二、基于OAuth2和JWT的SSO实现步骤

1. 系统架构设计

假设我们的系统包含以下模块:

  • 认证中心(Auth Server):负责用户登录、Token签发与验证。
  • 资源服务(Resource Server):多个子系统,依赖认证中心验证Token。
  • 客户端(Client):前端页面,负责发起登录请求和携带Token。

系统交互流程如下:

  1. 用户通过客户端访问某个子系统。
  2. 子系统发现用户未登录,重定向到认证中心。
  3. 用户在认证中心完成登录,认证中心返回Token。
  4. 客户端携带Token访问子系统,子系统验证Token有效性后返回资源。
sequenceDiagram
    participant Client as 前端客户端
    participant AuthServer as 认证中心
    participant ResourceServer as 资源服务

    Client->>ResourceServer: 请求资源
    ResourceServer-->>Client: 返回未授权提示,重定向到认证中心
    Client->>AuthServer: 发起登录请求
    AuthServer-->>Client: 返回登录页面
    Client->>AuthServer: 提交用户名密码
    AuthServer-->>Client: 返回Token
    Client->>ResourceServer: 携带Token请求资源
    ResourceServer->>AuthServer: 验证Token
    AuthServer-->>ResourceServer: 返回验证结果
    ResourceServer-->>Client: 返回资源

2. 配置认证中心(Auth Server)

认证中心需要支持OAuth2协议,并使用JWT作为Token格式。

(1) 添加依赖

在认证中心的pom.xml中添加以下依赖:

<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-security</artifactId>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>
(2) 配置OAuth2

application.yml中配置OAuth2相关信息:

spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          jwk-set-uri: http://localhost:8080/auth/jwks
(3) 实现Token签发逻辑

创建一个Controller用于签发Token:

@RestController
public class AuthController {

    @PostMapping("/login")
    public ResponseEntity<String> login(@RequestBody Map<String, String> credentials) {
        String username = credentials.get("username");
        String password = credentials.get("password");

        // 验证用户名和密码
        if ("admin".equals(username) && "123456".equals(password)) {
            String token = Jwts.builder()
                    .setSubject(username)
                    .setExpiration(new Date(System.currentTimeMillis() + 3600000)) // 1小时过期
                    .signWith(SignatureAlgorithm.HS256, "secretKey".getBytes())
                    .compact();
            return ResponseEntity.ok(token);
        }
        return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Invalid credentials");
    }
}

3. 配置资源服务(Resource Server)

资源服务需要验证来自认证中心的Token。

(1) 添加依赖

资源服务也需要引入OAuth2相关依赖。

(2) 配置Token验证

application.yml中配置Token验证逻辑:

spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: http://localhost:8080/auth
(3) 实现资源保护

使用Spring Security保护资源:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/api/**").authenticated() // 保护/api路径
                .and()
                .oauth2ResourceServer().jwt();
    }
}

4. 客户端实现

客户端需要在每次请求中携带Token。可以使用JavaScript拦截器实现:

axios.interceptors.request.use(config => {
    const token = localStorage.getItem('token');
    if (token) {
        config.headers['Authorization'] = `Bearer ${token}`;
    }
    return config;
});

三、扩展讨论

  1. Token刷新机制:为了防止Token过期导致频繁登录,可以通过Refresh Token机制自动刷新Token。
  2. 分布式Session管理:在多节点部署时,可以使用Redis存储Session信息以实现共享。
  3. 安全性增强:对Token加入更多校验规则,如IP绑定、设备指纹等。