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:

<!-- Sa-Token 权限认证 -->
<dependency>
    <groupId>cn.dev33</groupId>
    <artifactId>sa-token-spring-boot-starter</artifactId>
    <version>1.24.0</version>
</dependency>

Configure Sa-Token in application.yml (disable token read from cookie, enable header token):

# 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

Login Authentication

Add a login endpoint in UmsAdminController:

@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);
    }
}

Implement login logic in UmsAdminServiceImpl using StpUtil.login:

@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;
    }
}

Add a test endpoint to check login status (returns true when logged in).

@ControllerAdvice
public class GlobalExceptionHandler {
    @ResponseBody
    @ExceptionHandler(value = NotLoginException.class)
    public CommonResult handleNotLoginException(NotLoginException e) {
        return CommonResult.unauthorized(e.getMessage());
    }
}

Role Authentication

Implement StpInterface to provide role and permission lists for a user:

@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());
    }
}

Configure route rules in SaTokenConfig to enforce role checks:

@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("/**");
    }
}

Handle NotRoleException globally:

@ControllerAdvice
public class GlobalExceptionHandler {
    @ResponseBody
    @ExceptionHandler(value = NotRoleException.class)
    public CommonResult handleNotRoleException(NotRoleException e) {
        return CommonResult.forbidden(e.getMessage());
    }
}

Permission Authentication

Define permission checks in the same interceptor:

@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("/**");
    }
}

Handle NotPermissionException globally:

@ControllerAdvice
public class GlobalExceptionHandler {
    @ResponseBody
    @ExceptionHandler(value = NotPermissionException.class)
    public CommonResult handleNotPermissionException(NotPermissionException e) {
        return CommonResult.forbidden(e.getMessage());
    }
}

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.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

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

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.