Mastering Sa-Token: Simplify SpringBoot Authentication and Authorization
This guide walks you through integrating the lightweight Sa-Token framework into a SpringBoot project, covering dependency setup, configuration, login, role and permission checks, as well as global exception handling, with complete code examples and practical screenshots.
Sa-Token Overview
Sa-Token is a lightweight Java permission authentication framework that handles login authentication, permission checks, session management, single sign‑on, OAuth2.0, and micro‑service gateway authentication.
It is easy to integrate, works out‑of‑the‑box, and often requires only a single line of code to enable a feature.
Usage
Integrate Sa-Token into a SpringBoot project to implement common authentication and authorization functions such as login, role, and permission checks.
Integration and Configuration
Add the Sa-Token starter dependency to
pom.xml:
<code><!-- Sa-Token 权限认证 -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot-starter</artifactId>
<version>1.24.0</version>
</dependency></code>Configure Sa-Token in
application.yml(disable token read from cookie, enable header token):
<code># Sa-Token配置
sa-token:
token-name: Authorization
timeout: 2592000
activity-timeout: -1
is-concurrent: true
is-share: false
token-style: uuid
is-log: false
is-read-cookie: false
is-read-head: true</code>Login Authentication
Add a login endpoint in
UmsAdminController:
<code>@Controller
@Api(tags = "UmsAdminController", description = "后台用户管理")
@RequestMapping("/admin")
public class UmsAdminController {
@Autowired
private UmsAdminService adminService;
@ApiOperation(value = "登录以后返回token")
@RequestMapping(value = "/login", method = RequestMethod.POST)
@ResponseBody
public CommonResult login(@RequestParam String username, @RequestParam String password) {
SaTokenInfo saTokenInfo = adminService.login(username, password);
if (saTokenInfo == null) {
return CommonResult.validateFailed("用户名或密码错误");
}
Map<String, String> tokenMap = new HashMap<>();
tokenMap.put("token", saTokenInfo.getTokenValue());
tokenMap.put("tokenHead", saTokenInfo.getTokenName());
return CommonResult.success(tokenMap);
}
}
</code>Implement login logic in
UmsAdminServiceImplusing
StpUtil.login:
<code>@Slf4j
@Service
public class UmsAdminServiceImpl implements UmsAdminService {
@Override
public SaTokenInfo login(String username, String password) {
SaTokenInfo saTokenInfo = null;
AdminUser adminUser = getAdminByUsername(username);
if (adminUser == null) {
return null;
}
if (!SaSecureUtil.md5(password).equals(adminUser.getPassword())) {
return null;
}
// Password verified, log in with one line
StpUtil.login(adminUser.getId());
// Get token info of the current user
saTokenInfo = StpUtil.getTokenInfo();
return saTokenInfo;
}
}
</code>Add a test endpoint to check login status (returns
truewhen logged in).
<code>@ControllerAdvice
public class GlobalExceptionHandler {
@ResponseBody
@ExceptionHandler(value = NotLoginException.class)
public CommonResult handleNotLoginException(NotLoginException e) {
return CommonResult.unauthorized(e.getMessage());
}
}
</code>Role Authentication
Implement
StpInterfaceto provide role and permission lists for a user:
<code>@Component
public class StpInterfaceImpl implements StpInterface {
@Autowired
private UmsAdminService adminService;
@Override
public List<String> getPermissionList(Object loginId, String loginType) {
AdminUser adminUser = adminService.getAdminById(Convert.toLong(loginId));
return adminUser.getRole().getPermissionList();
}
@Override
public List<String> getRoleList(Object loginId, String loginType) {
AdminUser adminUser = adminService.getAdminById(Convert.toLong(loginId));
return Collections.singletonList(adminUser.getRole().getName());
}
}
</code>Configure route rules in
SaTokenConfigto enforce role checks:
<code>@Configuration
public class SaTokenConfig implements WebMvcConfigurer {
@Autowired
private IgnoreUrlsConfig ignoreUrlsConfig;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new SaRouteInterceptor((req, resp, handler) -> {
List<String> ignoreUrls = ignoreUrlsConfig.getUrls();
// Login authentication for all non‑whitelisted paths
SaRouter.match(Collections.singletonList("/**"), ignoreUrls, StpUtil::checkLogin);
// Role authentication
SaRouter.match("/brand/listAll", () -> {
StpUtil.checkRoleOr("ROLE_ADMIN", "ROLE_USER");
SaRouter.stop();
});
SaRouter.match("/brand/**", () -> StpUtil.checkRole("ROLE_ADMIN"));
})).addPathPatterns("/**");
}
}
</code>Handle
NotRoleExceptionglobally:
<code>@ControllerAdvice
public class GlobalExceptionHandler {
@ResponseBody
@ExceptionHandler(value = NotRoleException.class)
public CommonResult handleNotRoleException(NotRoleException e) {
return CommonResult.forbidden(e.getMessage());
}
}
</code>Permission Authentication
Define permission checks in the same interceptor:
<code>@Configuration
public class SaTokenConfig implements WebMvcConfigurer {
@Autowired
private IgnoreUrlsConfig ignoreUrlsConfig;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new SaRouteInterceptor((req, resp, handler) -> {
List<String> ignoreUrls = ignoreUrlsConfig.getUrls();
SaRouter.match(Collections.singletonList("/**"), ignoreUrls, StpUtil::checkLogin);
// Permission checks for brand APIs
SaRouter.match("/brand/listAll", () -> StpUtil.checkPermission("brand:read"));
SaRouter.match("/brand/create", () -> StpUtil.checkPermission("brand:create"));
SaRouter.match("/brand/update/{id}", () -> StpUtil.checkPermission("brand:update"));
SaRouter.match("/brand/delete/{id}", () -> StpUtil.checkPermission("brand:delete"));
SaRouter.match("/brand/list", () -> StpUtil.checkPermission("brand:read"));
SaRouter.match("/brand/{id}", () -> StpUtil.checkPermission("brand:read"));
})).addPathPatterns("/**");
}
}
</code>Handle
NotPermissionExceptionglobally:
<code>@ControllerAdvice
public class GlobalExceptionHandler {
@ResponseBody
@ExceptionHandler(value = NotPermissionException.class)
public CommonResult handleNotPermissionException(NotPermissionException e) {
return CommonResult.forbidden(e.getMessage());
}
}
</code>Conclusion
Through practical experiments with Sa-Token, we find its API design elegant and much easier to use than Shiro or Spring Security. Sa-Token offers a comprehensive set of permission‑related features and standard solutions such as OAuth2 and distributed session management, making it worth further exploration.
macrozheng
Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.