Sa-Token 1.39.0 Deep Dive: Source Code, SSO, Multi-Tenancy & Framework Comparison

This article provides a comprehensive technical analysis of Sa-Token 1.39.0, covering source code architecture, scenario-based configurations for JWT/stateless auth, mobile multi-device, RBAC admin panels, and SaaS multi-tenancy, plus unit testing patterns, common misconceptions, performance comparisons with Spring Security and Shiro, and production hardening practices.

CodeSmart Hoops
CodeSmart Hoops
CodeSmart Hoops
Sa-Token 1.39.0 Deep Dive: Source Code, SSO, Multi-Tenancy & Framework Comparison

8. Scenario-Based Discussion

8.1 Frontend-Backend Separation: JWT + Stateless

In frontend-backend separation (Vue/React), tokens are passed via headers. Configuration example:

sa-token:
  token-name: Authorization
  is-read-cookie: false
  is-read-header: true
  token-prefix: "Bearer"

CORS and SaInterceptor configuration:

@Configuration
public class CorsConfig implements WebMvcConfigurer {
  @Override
  public void addCorsMappings(CorsRegistry registry) {
    registry.addMapping("/**")
      .allowedOriginPatterns("*")
      .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
      .allowedHeaders("*")
      .allowCredentials(true)
      .maxAge(3600);
  }
}

@Configuration
public class SaTokenConfig implements WebMvcConfigurer {
  @Override
  public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(new SaInterceptor(handle -> StpUtil.checkLogin()))
      .addPathPatterns("/**")
      .excludePathPatterns("/auth/login", "/auth/register", "/swagger-ui/**", "/v3/api-docs/**");
  }
}

Frontend JavaScript example storing token in localStorage and sending via Authorization header.

JWT mode enables stateless auth by encoding user info into the token:

<dependency>
  <groupId>cn.dev33</groupId>
  <artifactId>sa-token-jwt</artifactId>
  <version>1.39.0</version>
</dependency>
SaTokenConfigure configure = new SaTokenConfigure()
  .setTokenStyle("jwt");

Comparison table: stateful (Redis) vs stateless (JWT) across token size, server storage, logout, user info updates, distributed support, security, and applicable scenarios.

8.2 Mobile APP: Multi-Device Independence

Mobile users may log in on phone, tablet, PC. Sa-Token's multi-device mode:

sa-token:
  is-concurrent: true
  is-share: false
  token-style: uuid

Controller example with device-specific login and switching:

@RestController
@RequestMapping("/app/auth")
public class AppAuthController {
  @PostMapping("/login")
  public Result<String> login(@RequestParam String username,
                              @RequestParam String password,
                              @RequestParam(defaultValue = "Mobile") String device) {
    User user = userService.login(username, password);
    if (user == null) return Result.error("登录失败");
    StpUtil.login(user.getId(), device);
    return Result.success(StpUtil.getTokenValue());
  }
  @PostMapping("/switch-device")
  public Result<String> switchDevice(@RequestParam String device) {
    StpUtil.switchDevice(device);
    return Result.success(StpUtil.getTokenValue());
  }
}

8.3 Admin Panel: Roles + Permissions (RBAC)

Service implementation storing permissions and roles in session:

@Service
public class AuthServiceImpl implements AuthService {
  @Override
  public void setPermission(Long userId) {
    List<String> permissions = permissionMapper.selectByUserId(userId);
    StpUtil.getSession().set("permission", permissions);
  }
  @Override
  public List<String> getPermissionList(Object loginId) {
    return StpUtil.getSessionByLoginId(loginId).get("permission", List.class);
  }
  @Override
  public void setRole(Long userId) {
    List<String> roles = roleMapper.selectByUserId(userId);
    StpUtil.getSession().set("role", roles);
  }
}

Data model diagram showing User, User_Role, Role, Role_Permission, Permission tables.

8.4 SaaS Multi-Tenancy: Multiple Account Systems

Each tenant gets isolated user/admin systems via StpLogic per tenant:

public class TenantStpLogic {
  private final String tenantId;
  private final StpLogic stpLogic;
  public TenantStpLogic(String tenantId) {
    this.tenantId = tenantId;
    this.stpLogic = new StpLogic("tenant:" + tenantId);
  }
  public void login(Object id) { stpLogic.login(id); }
  public boolean isLogin() { return stpLogic.isLogin(); }
  public Object getLoginId() { return stpLogic.getLoginId(); }
}

ThreadLocal-based TenantContext and interceptor extracting X-Tenant-Id header.

9. Source Code Analysis

9.1 StpLogic Interface Design

Core interface using Facade pattern. Architecture diagram: StpLogic interface → StpUtil (facade) / custom StpLogic → SaTokenManager → SaSessionDao → Memory/Redis/ZooKeeper. Benefits: unified API, easy extension via custom StpLogic, multi-account isolation by instantiating separate StpLogic per account type.

9.2 Sa-Token Filter Chain

Simpler than Spring Security's 10+ filters. Single SaInterceptor handling checkLogin, checkPermission, checkRole. Core preHandle logic skips @SaIgnore annotated methods, then runs authentication.

9.3 SSO Authentication Flow

Based on code mode similar to OAuth2 authorization code flow. Includes architecture diagram image.

9.4 Permission Annotation Scanning

@SaCheckPermission and @SaCheckRole implemented via Spring AOP. SaAnnotationInterceptor scans method annotations and calls StpUtil.checkPermission/checkRole. Comparison table: annotation-style (declarative, needs AOP), API-style (flexible, couples with business), interceptor-style (global, complex config).

10. Unit Testing

10.1 Mock Testing

Using SaTokenTestKit and StpUtil.login in @SpringBootTest with MockMvc.

10.2 Permission Verification Tests

Tests for hasPermission, hasRole, and checkPermission throwing NotPermissionException.

10.3 SSO Integration Test

Full flow: access client → redirect to SSO-Server → login → return to client with authenticated session.

10.4 Redis Storage Test

Verifies token key exists in Redis after login (key format: satoken:login:token:{tokenValue}) and is deleted after logout. Tests token timeout with 65s sleep.

11. Common Misconceptions

Misconception 1: "Sa-Token is insecure"

Security depends on usage: HTTPS, token expiry, 2FA for sensitive ops, permission granularity. Framework follows best practices.

Misconception 2: "Only for simple auth"

Feature comparison table across Sa-Token, Spring Security, Shiro covering login, permissions, roles, SSO, OAuth2, 2FA, multi-device, session management, remember-me, kick-offline, annotation auth, route auth, temporary tokens. Sa-Token covers all natively.

Misconception 3: "No distributed support"

Storage options table: Memory (dev), Redis (production default, sa-token-redis-jackson), Redisson (advanced features), ZooKeeper (strong consistency), Etcd (microservices), MySQL (custom DAO).

Misconception 4: "Deeply bound to Spring"

Core module (sa-token-core) has zero Spring dependencies. Spring integration via optional starter. Example of non-Spring usage with StpUtil directly.

Misconception 5: "Worse performance than Spring Security"

Benchmark table: Sa-Token 1 interceptor vs Spring Security 10+ filters; login ~5ms vs ~8ms; permission check ~2ms vs ~4ms; lower memory. Note: reference values, real JMH testing needed.

Misconception 6: "Poor documentation"

Official docs at sa-token.cc with complete Chinese guides. Active GitHub Issues.

Misconception 7: "No enterprise adoption"

Used in multiple enterprises/projects. High GitHub stars/forks. Selection should match technical needs.

12. Comparative Analysis

12.1 Sa-Token vs Spring Security

Detailed table: API style (static one-liner vs filter chain config), learning curve (1 day vs 1-2 weeks), core concepts (StpUtil/Token/Permission vs Filter/Provider/Manager/Context), config (YAML+annotations vs Java Config), extensibility (implement StpLogic vs extend Filter/Provider), ecosystem (independent vs Spring-bound), security (framework provides basics, relies on config vs comprehensive defaults), suitable scenarios (small/medium, rapid dev vs large enterprise, high security), i18n (mainly Chinese vs multi-language), community (domestic active vs international active).

12.2 Sa-Token vs Shiro

Table: maintenance (active vs stable/low updates), API simplicity (one-liner vs Realm+SecurityManager config), SSO/OAuth2/2FA/multi-device (built-in vs manual), docs (complete Chinese vs abundant but partly outdated), Spring Boot integration (official starter vs manual), community (growing vs stable).

12.3 Sa-Token SSO vs OAuth2 SSO

Table: protocol (custom vs RFC standard), cross-language (Java only vs multi-language), complexity (simple vs medium), third-party integration (none vs WeChat/GitHub/etc), applicable scenarios (internal Java systems vs third-party auth), token type (custom vs Access+Refresh), grant modes (code only vs authorization_code, client_credentials, password, implicit). Includes architecture diagram.

13. Best Practices

13.1 Token Expiry Design

Table with recommended expiries: admin 2-8h (with active-timeout), frontend users 7-30d (remember-me), mobile 30d+refresh, sensitive ops 30min (Safe Token), temporary 10-30min. Config example with timeout=28800 (8h) and active-timeout=1800 (30min).

13.2 Permission Granularity Design

Three levels: module (user, order), operation (user:add, user:edit), data (own vs all). Naming convention: {module}:{operation}. Anti-patterns: super_admin (too coarse), user:add:user (redundant), Chinese names (i18n issues).

13.3 Redis Integration Config

Production Lettuce pool config (max-active 16, max-idle 8, min-idle 2, max-wait 1000ms) and Sa-Token settings (timeout, active-timeout, is-concurrent true, is-share false, token-style uuid, is-log false to avoid token leakage).

13.4 Security Hardening

Transport: HTTPS, token in header not URL (is-read-cookie false, is-read-header true). Token management: reasonable expiry/active-timeout, 2FA for sensitive ops, auto cleanup (Sa-Token handles expired data). Permissions: least privilege, regular audits, refresh session on permission change. Attack prevention: captcha on login, failed attempt limiting (example code with 5 attempts/30min lockout), anomaly monitoring.

14. Summary

14.1 Quick Reference Table

Key points: positioning (lightweight Java auth, simple API, rich features), core APIs (StpUtil.login, checkLogin, checkPermission), core interface (StpLogic), login (one line), permission/role checks (API + annotations), token storage (memory default, Redis for prod), multi-device (independent/mutex), SSO (built-in server/client), OAuth2 (built-in), 2FA (StpUtil.openSafe + @SaCheckSafe), suitable for small/medium domestic projects, 1-day learning curve.

14.2 Core Code Cheatsheet

// ---- Basic Operations ----
StpUtil.login(userId);          // Login
StpUtil.logout();               // Logout
StpUtil.isLogin();              // Check login
StpUtil.getLoginId();           // Get account ID
StpUtil.getTokenValue();        // Get token

// ---- Permission Operations ----
StpUtil.checkPermission("user:add");  // Verify permission
StpUtil.hasPermission("user:add");   // Has permission
StpUtil.getPermissionList();         // Get permission list

// ---- Role Operations ----
StpUtil.checkRole("admin");          // Verify role
StpUtil.hasRole("admin");            // Has role
StpUtil.getRoleList();               // Get role list

// ---- Session Operations ----
StpUtil.getSession().set("key", value);  // Set session data
StpUtil.getSession().get("key");         // Get session data

// ---- 2FA ----
StpUtil.openSafe(1800);         // Open 2FA (30min)
StpUtil.closeSafe();            // Close 2FA
StpUtil.isSafe();               // Check 2FA status

// ---- Kick Offline ----
StpUtil.logoutByLoginId(userId);  // Kick user
StpUtil.kickout(device);          // Kick device

15. Interview Self-Test

10 questions mapping to article sections: core interface/pattern, one-line login internals, three token styles, 2FA purpose/usage, multi-account vs single-account, distributed support/storage options, Sa-Token SSO vs OAuth2 SSO tradeoffs, frontend-backend token passing, @SaCheckPermission AOP implementation, production hardening recommendations.

16. References

Sa-Token Official Docs — guides, core features, advanced

Sa-Token GitHub — source and issues

Sa-Token vs Spring Security — official comparison

Sa-Token SSO Docs

Sa-Token OAuth2 Docs

Spring Security Reference

Apache Shiro Reference

RFC 6749 OAuth 2.0

Sa-Token Multi-Account Examples

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.

Source Code AnalysisBest Practicesmulti-tenancyRBACssoSa-TokenJava AuthenticationSpring Security Comparison
CodeSmart Hoops
Written by

CodeSmart Hoops

A working programmer who loves coding and basketball. By day I debug code; by night I dissect tactics. I write articles to document my journey, focusing on Java, AI, Python and other programming topics, with occasional posts about basketball, English, and books. Hope it's helpful—thanks for following and support.

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.