在开发企业级应用时,经常会遇到多账号体系并存的情况。以电商系统为例,后台管理员使用sys_user表进行管理,而前端用户则使用ums_member表。这两种用户虽然都存在于同一个系统中,但他们的权限、功能和操作流程完全不同。
传统做法是直接修改SpringSecurity的配置来适配新需求,但这会带来几个问题:首先,SpringSecurity的学习曲线较陡峭,不熟悉的开发者很容易踩坑;其次,直接修改原有认证逻辑存在风险,可能影响现有功能;最重要的是,两种认证逻辑混杂在一起,后期维护会越来越困难。
我在实际项目中就遇到过这种情况:原本运行良好的后台管理系统,在接入移动端用户认证后开始出现各种奇怪的权限问题。调试时发现两种认证逻辑相互干扰,最终不得不花大量时间重构。
SpringSecurity作为老牌安全框架,功能强大但配置复杂。它更适合需要细粒度控制的后台管理系统。而Sa-Token作为新兴的轻量级框架,具有以下优势:
实测下来,对于会员系统的登录、登出、会话管理这些基础功能,Sa-Token的代码量只有SpringSecurity的1/3左右。比如实现登录功能:
java复制// Sa-Token实现
@PostMapping("/login")
public AjaxResult login(@RequestBody LoginBody loginBody) {
// 验证账号密码...
StpUtil.login(userId);
return AjaxResult.success().put("token", StpUtil.getTokenValue());
}
// SpringSecurity实现
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin()
.loginProcessingUrl("/login")
.successHandler((req,resp,auth)->{/* 处理逻辑 */})
.failureHandler((req,resp,e)->{/* 处理逻辑 */});
// 还需要配套的UserDetailsService实现...
}
核心思路是通过URL前缀进行物理隔离:
/admin/**:走SpringSecurity认证,用于后台管理/api/**:走Sa-Token认证,用于APP/小程序这种设计有三大好处:
具体实现时需要关注以下关键点:
首先在ruoyi-common的pom.xml中添加依赖:
xml复制<!-- Sa-Token核心包 -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot-starter</artifactId>
<version>1.34.0</version>
</dependency>
<!-- Redis集成(推荐) -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-dao-redis-jackson</artifactId>
<version>1.34.0</version>
</dependency>
修改SecurityConfig.java,放行API路径:
java复制@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
// 放行API相关路径
.antMatchers("/api/**").permitAll()
// 其他配置保持不变...
.anyRequest().authenticated();
}
新建SaTokenConfig.java:
java复制@Configuration
public class SaTokenConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new SaRouteInterceptor())
.addPathPatterns("/api/**")
.excludePathPatterns("/api/auth/login");
}
@Bean
public StpLogic stpLogic() {
// 使用独立的StpLogic,避免与SpringSecurity冲突
return new StpLogic("member");
}
}
会员登录接口示例:
java复制@RestController
@RequestMapping("/api/auth")
public class AuthApi {
@PostMapping("/login")
public AjaxResult login(@Valid @RequestBody LoginDTO dto) {
// 1. 验证账号密码
Member member = memberService.verifyLogin(dto);
// 2. 登录并返回token
StpUtil.login(member.getId());
// 3. 组装返回数据
LoginVO vo = new LoginVO();
vo.setToken(StpUtil.getTokenValue());
vo.setExpiresIn(StpUtil.getTokenTimeout());
return AjaxResult.success(vo);
}
}
获取用户信息接口:
java复制@RestController
@RequestMapping("/api/member")
public class MemberApi {
@GetMapping("/info")
public AjaxResult info() {
// 1. 检查登录状态
if(!StpUtil.isLogin()) {
throw new NotLoginException();
}
// 2. 获取用户信息
Long memberId = StpUtil.getLoginIdAsLong();
MemberInfoVO info = memberService.getInfo(memberId);
return AjaxResult.success(info);
}
}
现象:两种认证的Token互相覆盖。
解决方案:为Sa-Token指定独立的token名称:
properties复制# application.yml
sa-token:
token-name: satoken-member
现象:Sa-Token校验时误用了SpringSecurity的权限数据。
解决方案:使用独立的StpLogic:
java复制// 在配置类中声明
@Bean
public StpLogic stpLogic() {
return new StpLogic("member");
}
现象:两套认证的超时时间不一致导致体验割裂。
解决方案:统一配置:
properties复制sa-token:
timeout: 86400 # 24小时
activity-timeout: 1800 # 30分钟无操作过期
我在实际项目中采用这种架构后,后台管理系统的稳定性得到了保证,同时APP端的开发效率提升了40%。新来的移动端开发者只需要了解Sa-Token就能快速上手,不再需要深入理解复杂的SpringSecurity配置。