一、系统架构调整
- 用户中心:保持现有的用户登录、注册接口不变。
- 多个项目:前后端分离,保持现有逻辑不变。
- 网关服务:新增或配置网关服务,处理所有请求并进行 Token 校验和转发。
- 统一 Token 管理:通过 Sa-Token 统一管理 Token,前后端项目依然调用用户中心接口,但通过网关服务进行 Token 校验和转发。
二、具体改造步骤
1. 引入 Sa-Token 进行统一 Token 管理
在用户中心中引入 Sa-Token,实现登录时生成 Token,并返回给客户端。
用户中心登录接口示例:
@RestController
@RequestMapping("/auth")
public class AuthController {
@PostMapping("/login")
public SaResult login(@RequestParam String username, @RequestParam String password) {
// 进行用户名和密码校验
if (checkCredentials(username, password)) {
StpUtil.login(username);
return SaResult.ok("登录成功").set("token", StpUtil.getTokenValue());
}
return SaResult.error("登录失败");
}
private boolean checkCredentials(String username, String password) {
// 检查用户名和密码逻辑
return true; // 假设校验成功
}
}
用户中心 Token 校验接口示例:
@RestController
@RequestMapping("/auth")
public class AuthController {
@GetMapping("/check")
public SaResult checkToken(@RequestParam String token) {
if (StpUtil.isLogin(token)) {
return SaResult.ok("Token 有效");
}
return SaResult.error("Token 无效");
}
}
2. 配置 Sa-Token 在各项目中的使用
在每个项目的配置文件中添加 Sa-Token 配置,确保所有项目使用相同的 Token 配置。
application.yml
sa-token:
token-name: satoken
timeout: 86400 # Token 过期时间,单位秒
activity-timeout: -1 # Token 最后活跃时间
is-concurrent: false # 是否允许多地登录
is-share: true # 是否共享会话
3. 配置网关服务
网关服务负责拦截所有请求,并对 Token 进行校验。使用 Spring Cloud Gateway 作为示例:
网关服务 Token 校验过滤器:
@Component
public class TokenFilter implements GlobalFilter, Ordered {
@Autowired
private RestTemplate restTemplate;
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String token = exchange.getRequest().getHeaders().getFirst("Authorization");
if (token != null && checkToken(token)) {
return chain.filter(exchange);
}
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
private boolean checkToken(String token) {
// 调用用户中心的 Token 校验接口
String url = "http://user-center/auth/check?token=" + token;
ResponseEntity<SaResult> response = restTemplate.getForEntity(url, SaResult.class);
return response.getStatusCode() == HttpStatus.OK && response.getBody().getCode() == 200;
}
@Override
public int getOrder() {
return -100;
}
}
4. 前端项目处理登录逻辑
前端项目在用户登录成功后,将 Token 存储在浏览器的本地存储或 Cookie 中,并在每次请求时携带 Token。
前端登录逻辑示例:
async function login(username, password) {
try {
const response = await axios.post('/auth/login', { username, password });
if (response.data.code === 200) {
// 登录成功,存储 Token
localStorage.setItem('token', response.data.data.token);
return true;
}
return false;
} catch (error) {
console.error('登录失败', error);
return false;
}
}
// 在每次请求时携带 Token
axios.interceptors.request.use(config => {
const token = localStorage.getItem('token');
if (token) {
config.headers.Authorization = token;
}
return config;
}, error => {
return Promise.reject(error);
});
三、总结
通过上述步骤,可以在不改变现有业务逻辑的基础上,实现三个项目的单点登录:
- 用户中心:继续处理用户登录和注册,并通过 Sa-Token 生成和验证 Token。
- 各个项目:通过网关服务转发请求和校验 Token,不需要改变现有的业务逻辑。
- 网关服务:统一拦截请求并校验 Token,实现集中管理和验证。
这种方式可以最小化改造工作量,实现单点登录的目标。