Sa-Token Deep Dive: 10 Interview Questions on Auth, Multi-Account & SSO

This article explores 10 key Sa-Token interview questions covering core interfaces, one-line login internals, token styles, second-level authentication, multi-account architecture, distributed storage options, SSO comparisons, token passing strategies, permission annotation implementation, and production security hardening.

CodeSmart Hoops
CodeSmart Hoops
CodeSmart Hoops
Sa-Token Deep Dive: 10 Interview Questions on Auth, Multi-Account & SSO

Interview Self-Test

Q1: What is Sa-Token's core interface? What design pattern does it embody? — Chapter: Concept Definition

Q2: What is the one-line API for Sa-Token login? What happens underneath? — Chapter: Quick Start

Q3: What are Sa-Token's three token styles? How do their use cases differ? — Chapter: Advanced Features

Q4: What problem does Sa-Token's second-level authentication (Sub-Login) solve? How to use it? — Chapter: Advanced Features

Q5: How does Sa-Token implement multi-account systems? How does it differ from single-account? — Chapter: Spring Boot Integration

Q6: How does Sa-Token support distributed deployment? What storage options exist? — Chapter: Common Pitfalls

Q7: What are the pros/cons of Sa-Token SSO vs OAuth2 SSO? How to choose? — Chapter: Comparative Analysis

Q8: In frontend-backend separation, how is Sa-Token's token passed? What to watch for? — Chapter: Scenario Discussion

Q9: How is Sa-Token's @SaCheckPermission annotation implemented under the hood? — Chapter: Source Code Analysis

Q10: What security hardening recommendations exist for Sa-Token in production? — Chapter: Best Practices

Q1: Sa-Token's Core Interface and Design Patterns

Answer: Sa-Token's core interface is StpLogic; all authentication and authorization operations go through this interface.

// StpLogic core interface (partial methods)
public interface StpLogic {
    // Login
    void login(Object id);
    void login(Object id, boolean rememberMe);
    // Logout
    void logout();
    void logout(Object loginId);
    // Authentication check
    void checkLogin();
    // Permission check
    void checkPermission(String permission);
    void checkRole(String role);
    // Token operations
    String getTokenValue();
    void setTokenValue(String tokenValue, int timeout);
    // Session operations
    SaSession getSession();
    SaSession getSessionByLoginId(Object loginId);
    // Online users
    List<Object> getLoginIdList();
    int getTokenSessionTimeout();
}

Design Patterns:

Interface Segregation: Auth and authz separated — StpLogic defines core, StpUtil provides static calls

Strategy: Swappable storage implementations — Redis, Memory, InfluxDB, etc.

Singleton: Global unique StpLogic instance — StpLogic DEFAULT static instance

Adapter: Adapt to different frameworks — Sa-Token-Servlet adapter

// StpUtil is StpLogic's static utility class (Singleton)
public class StpUtil {
    public static final StpLogic stpLogic = new StpLogic("/user");

    public static void login(Object id) {
        stpLogic.login(id);
    }

    public static void checkLogin() {
        stpLogic.checkLogin();
    }
}

Reference: Sa-Token认证框架全解析 - Concept Definition

Q2: One-Line Login API and Underlying Flow

Answer: StpUtil.login(10001); // One line completes login

Underlying Execution Flow:

1. Generate Token (UUID or Snowflake ID)
    token = UUID.randomUUID().toString()

2. Store Token → userId mapping
    redis.set("satoken:login:login-token:" + token, "10001", timeout)

3. Store userId → Session mapping
    redis.set("satoken:login:login-session:10001", sessionData)

4. Write Cookie (or return to frontend)
    response.addCookie("satoken", token)
// Simplified source code
public void login(Object loginId) {
    // 1. Generate Token
    String token = createToken(loginId);
    // 2. Write to storage (Redis)
    String loginTokenKey = SpConsts.LOGIN_TOKEN_SPILIT + token;
    SaManager.getSaTokenStore().set(loginTokenKey, loginId, SaManager.getTokenTimeout);
    // 3. Create Session
    SaManager.getSaTokenStore().getSessionByLoginId(loginId);
    // 4. Write Cookie
    SaManager.getTokenTop().setToken(token, SaManager.getTokenTimeout);
}

Reference: Sa-Token认证框架全解析 - Quick Start

Q3: Three Token Styles and Applicable Scenarios

Answer:

UUID: Format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx — Pros: Globally unique, extremely low collision probability — Cons: Long length (36 chars) — Use Case: General purpose

Simple-UUID: Format: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx — Pros: Removes hyphens, shorter length — Cons: Same security level as UUID — Use Case: Mobile, URL parameters

Random-32: Format: Random 32-char string — Pros: Fixed length, aesthetic — Cons: Randomness depends on algorithm — Use Case: Default recommended

# Configure token style
sa-token:
  token-style: random-32  # random-32 | uuid | simple-uuid
// Custom token generator
SaTokenStrategy.stpLogic.setTokenGenerator(new TokenGenerator() {
    @Override
    public String generateToken(Object loginId, String loginType) {
        // Snowflake algorithm generates unique ID
        return SnowflakeIdGenerator.generateId();
    }
});

Reference: Sa-Token认证框架全解析 - Advanced Features

Q4: Second-Level Authentication (Sub-Login)

Problem Solved: On an already logged-in account, perform secondary authentication for specific functional areas, similar to Alipay's "payment password".

Scenario: User logged in, now wants to change password/view sensitive data
    Requires user to re-enter password to confirm identity before allowing operation

Second-level auth flow:
User logged in ──► Access sensitive area ──► Trigger second-level auth
    ──► Re-verify (password/captcha) ──► Second-level auth success
    ──► Gain access permission
// 1. Check if second-level auth passed
if (!StpUtil.isPermit("user:password")) {
    // Not passed, redirect to verification page
}

// 2. After password verification, grant second-level auth
StpUtil.permit("user:password", 300);  // Valid for 5 minutes

// 3. Access protected function
@SaCheckPermission("user:password")
@GetMapping("/api/user/password")
public String getPassword() {
    return userService.getPassword(StpUtil.getLoginId());
}

Reference: Sa-Token认证框架全解析 - Advanced Features

Q5: Multi-Account System Implementation

Multi-Account System: Different modules in the same application use different account systems, each with independent authentication and authorization.

admin   ──► StpLogic   (Backend admin system)
user    ──► StpLogic   (Frontend user center)
open    ──► StpLogic   (Open platform API)
// Define three account systems
public class SaTool {
    // Backend admin
    public static final StpLogic ADMIN = new StpLogic("/admin");
    // Frontend user
    public static final StpLogic USER = new StpLogic("/user");
    // Open platform
    public static final StpLogic OPEN = new StpLogic("/open");
}

// Usage
SaTool.ADMIN.login(adminId);
SaTool.USER.login(userId);
SaTool.OPEN.login(openId);

// Verification
SaTool.ADMIN.checkLogin();
SaTool.USER.checkPermission("order:add");

Comparison:

Instance: Single-Account: One StpUtil | Multi-Account: Multiple StpLogic

Auth Isolation: Single-Account: None | Multi-Account: Fully independent

Token Isolation: Single-Account: Share one token | Multi-Account: Independent tokens each

Scenario: Single-Account: Single application | Multi-Account: Admin/Frontend/API separation

Reference: Sa-Token认证框架全解析 - Spring Boot Integration

Q6: Distributed Deployment and Storage Options

Distributed Storage Options:

Memory: Dependency: None — Scenario: Single-node deployment — Pros: Zero config — Cons: Not distributed

Redis: Dependency: redis plugin — Scenario: Distributed deployment — Pros: High performance, mature — Cons: Requires Redis

Redisson: Dependency: redisson plugin — Scenario: Distributed + distributed locks — Pros: Rich features — Cons: Heavy dependency

InfluxDB: Dependency: influxdb plugin — Scenario: High-concurrency writes — Pros: Time-series optimized — Cons: Small ecosystem

<!-- Redis Integration -->
<dependency>
    <groupId>cn.dev33</groupId>
    <artifactId>sa-token-dao-redis-jackson</artifactId>
    <version>1.39.0</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
# Configuration
sa-token:
  is-read-cookie: true   # Allow Cookie token passing
  is-log: false          # Disable logs in production

Distributed Storage Architecture:

┌──────────┐    ┌──────────┐    ┌──────────┐
│ Service1 │    │ Service2 │    │ Service3 │
│          │    │          │    │          │
└────┬─────┘    └────┬─────┘    └────┬─────┘
     │               │               │
     └───────────────┼───────────────┘
                     │
              ┌──────┴──────┐
              │    Redis    │
              │ (Unified)   │
              └─────────────┘

All services read/write same Redis, Token globally shared

Reference: Sa-Token认证框架全解析 - Common Pitfalls

Q7: Sa-Token SSO vs OAuth2 SSO Comparison

Answer:

Protocol Standard: Sa-Token SSO: Custom protocol | OAuth2 SSO: Standard protocol

Cross-Language: Sa-Token SSO: Java only | OAuth2 SSO: Any language

Integration Difficulty: Sa-Token SSO: Low | OAuth2 SSO: Medium

Third-Party Support: Sa-Token SSO: None | OAuth2 SSO: Keycloak, Auth0, etc.

Applicable Scenario: Sa-Token SSO: Java internal systems | OAuth2 SSO: Cross-language, external exposure

Sa-Token SSO Architecture:

┌──────────┐
│ SSO Auth │
│ Center   │
│ (Server) │
└────┬─────┘
     │
     ├────► App A (Client)
     ├────► App B (Client)
     └────► App C (Client)

OAuth2 SSO Architecture:

┌──────────┐
│ Auth     │
│ Server   │
│(Keycloak)│
└────┬─────┘
     │
     ├────► App A (Any language)
     ├────► App B (Any language)
     └────► Third-party apps (External)
// Sa-Token SSO Server
@PostMapping("/doLogin")
public String doLogin(@RequestParam String name, @RequestParam String pwd) {
    StpUtil.login(10001);
    return SsoClientUtils.login(name, pwd);
}

// Sa-Token SSO Client
@GetMapping("/callback")
public String callback(@RequestParam String code) {
    String token = SsoClientUtils.buildTokenByCode(code);
    StpUtil.login(token);
    return "Login successful";
}

Reference: Sa-Token认证框架全解析 - Comparative Analysis

Q8: Token Passing in Frontend-Backend Separation

Token Passing Solutions:

Solution 1: Response Header return (Sa-Token default)
  Login success ──► Server sets satoken in Response Header
  Subsequent requests ──► Browser auto-carries Cookie

Solution 2: Response Body return
  Login success ──► Return { token: "xxx" }
  Frontend stores ──► localStorage or sessionStorage
  Subsequent requests ──► Carry in Authorization Header

Solution 3: Cookie + Header hybrid
  HttpOnly Cookie storage (prevent XSS)
  Custom Header verification (prevent CSRF)
// Frontend-backend separation login
@PostMapping("/login")
public R login(@RequestBody LoginRequest req) {
    // Verify
    User user = userService.login(req.getUsername(), req.getPassword());
    StpUtil.login(user.getId());

    // Get Token
    String token = StpUtil.getTokenValue();

    // Return to frontend (frontend stores to localStorage)
    return R.ok("Login successful").data("token", token);
}

// Global interceptor
@Configuration
public class SaTokenConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new SaInterceptor(h -> {
            StpUtil.checkLogin();
        })).addPathPatterns("/**")
          .excludePathPatterns("/login", "/static/**");
    }
}

Considerations:

Cookie cross-domain: Configure CORS, set withCredentials

Token refresh: Dual token or sliding renewal

XSS reads Token: Use HttpOnly Cookie or in-memory storage

CSRF attack: Carry custom Header or use SameSite

Reference: Sa-Token认证框架全解析 - Scenario Discussion

Q9: @SaCheckPermission Annotation Implementation

@SaCheckPermission

is implemented based on AOP (Aspect-Oriented Programming) , performing permission checks before method execution.

Method call ──► AOP intercept ──► Read @SaCheckPermission annotation
                    │
                    ├─► StpUtil.checkPermission("user:add")
                    │
                    ├─► Get user permission list from Session
                    │
                    ├─► Match permission ──► Pass ──► Execute method
                    └─► Mismatch ──► Throw NotPermissionException
// Simplified source code
@Aspect
public class SaPermissionAspect {

    @Around("@annotation(saCheckPermission)")
    public Object around(ProceedingJoinPoint point, SaCheckPermission saCheckPermission) throws Throwable {
        // Execute permission check
        StpUtil.checkPermission(saCheckPermission.value());
        // Check passed, execute target method
        return point.proceed();
    }
}
// Usage examples
@SaCheckPermission("user:add")
@PostMapping("/user")
public R addUser(@RequestBody User user) {
    return R.ok("Added successfully");
}

// Multiple permissions (satisfy any one)
@SaCheckPermission(value = {"user:add", "user:update"}, mode = SaMode.OR)
@PutMapping("/user")
public R updateUser(@RequestBody User user) {
    return R.ok("Updated successfully");
}

// Multiple permissions (must satisfy all)
@SaCheckPermission(value = {"user:add", "user:export"}, mode = SaMode.AND)
@GetMapping("/user/export")
public R exportUsers() {
    return R.ok("Exported successfully");
}

Reference: Sa-Token认证框架全解析 - Source Code Analysis

Q10: Production Security Hardening Recommendations

Security Hardening Checklist:

Token Timeout: Set reasonable expiration — Configuration: activity-timeout: 1800 (30 min)

Concurrent Login Control: Limit online devices per account — Configuration: max-login-count: 3 Password Encryption: Verify encrypted password on login — Use BCrypt

Brute Force Prevention: Limit login failure attempts — Integrate Redis rate limiting

Token Encrypted Transport: HTTPS transmission — Full-site HTTPS

Log Desensitization: Don't log passwords/sensitive info — Disable is-log

Exception Handling: Unified exception responses — Custom NotLoginException handler

sa-token:
  timeout: 1800              # 30 minutes
  activity-timeout: 1800     # Active timeout
  max-login-count: 3         # Max 3 devices online simultaneously
  is-log: false              # Disable log output in production
  is-read-cookie: false      # Disable Cookie for frontend-backend separation
  token-name: Authorization  # Use Authorization Header
// Unified exception handling
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(NotLoginException.class)
    public R handleNotLogin(NotLoginException e) {
        return R.error(401, "Not logged in");
    }

    @ExceptionHandler(NotPermissionException.class)
    public R handleNotPermission(NotPermissionException e) {
        return R.error(403, "No permission");
    }

    @ExceptionHandler(NotRoleException.class)
    public R handleNotRole(NotRoleException e) {
        return R.error(403, "No role");
    }
}

Reference: Sa-Token认证框架全解析 - Best Practices

References

Sa-Token认证框架全解析 — Original article for this interview self-test

Sa-Token Official Documentation — https://sa-token.cc/

Spring Security Official Documentation — https://docs.spring.io/spring-security/reference/index.html

RFC 6749 - OAuth 2.0 — https://tools.ietf.org/html/rfc6749

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.

distributed systemsJavaAOPRedisSecurityauthenticationInterview PreparationssoMulti-AccountSa-Token
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.