Backend Development 13 min read

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.

macrozheng
macrozheng
macrozheng
Mastering Sa-Token: Simplify SpringBoot Authentication and Authorization

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>&lt;!-- Sa-Token 权限认证 --&gt;
&lt;dependency&gt;
    &lt;groupId&gt;cn.dev33&lt;/groupId&gt;
    &lt;artifactId&gt;sa-token-spring-boot-starter&lt;/artifactId&gt;
    &lt;version&gt;1.24.0&lt;/version&gt;
&lt;/dependency&gt;</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

UmsAdminServiceImpl

using

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

true

when 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

StpInterface

to 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

SaTokenConfig

to 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

NotRoleException

globally:

<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

NotPermissionException

globally:

<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.

javaauthenticationSpringBootPermission Managementauthorizationrole-based access controlSa-Token
macrozheng
Written by

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.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.