在微服务架构中,使用 Sa-Token 进行分布式认证和权限管理需要考虑到各个服务之间的通信和 Token
的共享。以下是一个详细的教程,介绍如何在微服务中使用 Sa-Token。
1. 微服务架构介绍
假设有以下几个微服务:
- AuthService: 负责用户认证和 Token 生成。
- UserService: 负责用户信息管理。
- OrderService: 负责订单管理。
2. 引入依赖
在每个微服务中引入 Sa-Token 的依赖。以 Maven 项目为例,可以在每个服务的 pom.xml
文件中添加以下依赖:
xml
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot-starter</artifactId>
<version>1.31.0</version>
</dependency>
3. 配置 Sa-Token
在每个微服务中配置 Sa-Token。在 application.yml
或 application.properties
文件中添加配置。例如:
yaml
sa-token:
token-name: satoken
timeout: 86400
activity-timeout: -1
is-read-cookie: true
is-log: false
is-splicing: false
4. AuthService 实现
AuthService 负责用户的认证和 Token 生成。
AuthController
java
import cn.dev33.satoken.stp.StpUtil;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/auth")
public class AuthController {
@PostMapping("/login")
public String login(@RequestParam String username, @RequestParam String password) {
// 假设这是从数据库中查找的用户信息
if ("admin".equals(username) && "123456".equals(password)) {
StpUtil.login(10001);
return "登录成功,Token: " + StpUtil.getTokenValue();
}
return "登录失败";
}
@PostMapping("/logout")
public String logout() {
StpUtil.logout();
return "注销成功";
}
}
5. 其他微服务的配置
其他微服务(如 UserService 和 OrderService)需要在请求中携带 Token 并进行验证。
配置全局拦截器
在每个微服务中配置全局拦截器以验证 Token。
java
import cn.dev33.satoken.interceptor.SaInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class SaTokenConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new SaInterceptor()).addPathPatterns("/**")
.excludePathPatterns("/auth/login", "/auth/logout");
}
}
UserController 示例
java
import cn.dev33.satoken.stp.StpUtil;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/user")
public class UserController {
@GetMapping("/info")
public String getUserInfo() {
StpUtil.checkLogin(); // 检查是否登录
int userId = StpUtil.getLoginIdAsInt();
// 根据 userId 获取用户信息(省略具体逻辑)
return "用户信息";
}
}
OrderController 示例
java
import cn.dev33.satoken.stp.StpUtil;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/order")
public class OrderController {
@GetMapping("/list")
public String getOrderList() {
StpUtil.checkLogin(); // 检查是否登录
int userId = StpUtil.getLoginIdAsInt();
// 根据 userId 获取订单列表(省略具体逻辑)
return "订单列表";
}
}
6. 微服务之间的调用
在微服务之间调用时,需要在请求头中携带 Token。可以使用 Feign Client 进行服务间调用。
Feign 配置
添加 Feign Client 依赖:
xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
创建 Feign Client
例如,在 UserService 中调用 OrderService:
java
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
@FeignClient(name = "order-service")
public interface OrderServiceClient {
@GetMapping("/order/list")
String getOrderList(@RequestHeader("satoken") String token);
}
在控制器中使用 Feign Client
java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private OrderServiceClient orderServiceClient;
@GetMapping("/orders")
public String getUserOrders() {
StpUtil.checkLogin(); // 检查是否登录
String token = StpUtil.getTokenValue();
return orderServiceClient.getOrderList(token);
}
}
7. 集成 Redis 实现分布式会话
为了在分布式系统中共享 Token,可以使用 Redis 存储会话信息。
引入 Redis 依赖
在 pom.xml
文件中添加 Redis 依赖:
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
配置 Redis
在 application.yml
中配置 Redis 连接信息:
yaml
spring:
redis:
host: localhost
port: 6379
启用 Redis 存储
在 Sa-Token 配置类中启用 Redis 存储:
java
import cn.dev33.satoken.dao.SaTokenDaoRedis;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
@Configuration
public class SaTokenConfig {
@Bean
public SaTokenDaoRedis saTokenDaoRedis(RedisConnectionFactory connectionFactory) {
return new SaTokenDaoRedis(connectionFactory);
}
}
8. 完整示例
以下是一个包含登录、注销、权限验证和微服务间调用的完整示例:
AuthService
java
@RestController
@RequestMapping("/auth")
public class AuthController {
@PostMapping("/login")
public String login(@RequestParam String username, @RequestParam String password) {
if ("admin".equals(username) && "123456".equals(password)) {
StpUtil.login(10001);
return "登录成功,Token: " + StpUtil.getTokenValue();
}
return "登录失败";
}
@PostMapping("/logout")
public String logout() {
StpUtil.logout();
return "注销成功";
}
}
UserService
java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private OrderServiceClient orderServiceClient;
@GetMapping("/info")
public String getUserInfo() {
StpUtil.checkLogin();
return "用户信息";
}
@GetMapping("/orders")
public String getUserOrders() {
StpUtil.checkLogin();
String token = StpUtil.getTokenValue();
return orderServiceClient.getOrderList(token);
}
}
@FeignClient(name = "order-service")
public interface OrderServiceClient {
@GetMapping("/order/list")
String getOrderList(@RequestHeader("satoken") String token);
}
OrderService
java
import cn.dev33.satoken.stp.StpUtil;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/order")
public class OrderController {
@GetMapping("/list")
public String getOrderList(@RequestHeader("satoken") String token) {
StpUtil.checkLogin(); // 检查是否登录
return "订单列表";
}
}
通过以上步骤,你已经完成了在微服务架构中使用 Sa-Token 进行分布式认证和权限管理的基本配置。你可以根据具体需求进行扩展和调整。