Master Microservice Authentication with Sa-Token and Spring Cloud Gateway

This tutorial walks through building a microservice authentication and authorization solution using Sa-Token, Spring Cloud Gateway, Nacos, and Redis, detailing the setup of gateway, authentication, and protected API services, configuration files, custom permission handling, and a complete demo with Postman.

macrozheng
macrozheng
macrozheng
Master Microservice Authentication with Sa-Token and Spring Cloud Gateway

Prerequisite Knowledge

We will use Nacos as the service registry, Spring Cloud Gateway as the API gateway, and Sa-Token for microservice permission management. The following articles provide background information.

Spring Cloud Gateway: Next‑gen API gateway service

Spring Cloud Alibaba: Using Nacos as registry and config center

Microservice Permission Solution with Spring Cloud Gateway + OAuth2

Sa-Token Tutorial

Application Architecture

The architecture follows the previous solution: the authentication service handles login, the gateway performs authentication and permission checks, and each API service contains its own business logic. All services share Sa-Token sessions via Redis.

micro-sa-token-common: shared DTOs such as UserDTO and CommonResult micro-sa-token-gateway: gateway service for request forwarding, login authentication, and permission verification

micro-sa-token-auth: authentication service exposing a login endpoint

micro-sa-token-api: protected API service accessed after gateway authentication

Solution Implementation

We will sequentially build the gateway, authentication, and API services.

micro-sa-token-gateway

First, set up the gateway service, which will handle authentication and authorization for all microservices.

Add the following dependencies to pom.xml:

<dependencies>
    <!-- Sa-Token permission (reactive) -->
    <dependency>
        <groupId>cn.dev33</groupId>
        <artifactId>sa-token-reactor-spring-boot-starter</artifactId>
        <version>1.24.0</version>
    </dependency>
    <!-- Sa-Token Redis integration (Jackson) -->
    <dependency>
        <groupId>cn.dev33</groupId>
        <artifactId>sa-token-dao-redis-jackson</artifactId>
        <version>1.24.0</version>
    </dependency>
    <!-- Redis connection pool -->
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-pool2</artifactId>
    </dependency>
    <!-- Common module -->
    <dependency>
        <groupId>com.macro.cloud</groupId>
        <artifactId>micro-sa-token-common</artifactId>
        <version>1.0.0</version>
    </dependency>
</dependencies>

Configure Redis and Sa-Token in application.yml:

spring:
  redis:
    database: 0
    port: 6379
    host: localhost
    password:

# Sa-Token configuration
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

Create SaTokenConfig to register a global filter, define authentication rules, and handle errors:

@Configuration
public class SaTokenConfig {
    /** Register Sa-Token global filter */
    @Bean
    public SaReactorFilter getSaReactorFilter() {
        return new SaReactorFilter()
            // Intercept all paths
            .addInclude("/**")
            // Exclude favicon
            .addExclude("/favicon.ico")
            // Authentication logic
            .setAuth(r -> {
                // Login authentication (all paths except login)
                SaRouter.match("/**", "/auth/user/login", StpUtil::checkLogin);
                // Permission checks for specific APIs
                SaRouter.match("/api/test/hello", () -> StpUtil.checkPermission("api:test:hello"));
                SaRouter.match("/api/user/info", () -> StpUtil.checkPermission("api:user:info"));
            })
            // Error handling
            .setError(e -> {
                ServerWebExchange exchange = SaReactorSyncHolder.getContent();
                exchange.getResponse().getHeaders().set("Content-Type", "application/json; charset=utf-8");
                return SaResult.error(e.getMessage());
            });
    }
}

Extend StpInterface to provide permission lists from the session:

/** Custom permission interface */
@Component
public class StpInterfaceImpl implements StpInterface {
    @Override
    public List<String> getPermissionList(Object loginId, String loginType) {
        UserDTO userDTO = (UserDTO) StpUtil.getSession().get("userInfo");
        return userDTO.getPermissionList();
    }
    @Override
    public List<String> getRoleList(Object loginId, String loginType) {
        return null;
    }
}

micro-sa-token-auth

Next, build the authentication service with a simple login endpoint.

Add the same dependencies as the gateway (Sa-Token, Redis, common module) to pom.xml.

Reuse the application.yml configuration shown above.

Create a login controller:

@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserServiceImpl userService;

    @RequestMapping(value = "/login", method = RequestMethod.POST)
    public CommonResult login(@RequestParam String username, @RequestParam String password) {
        SaTokenInfo saTokenInfo = userService.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 the service:

@Service
public class UserServiceImpl {
    private List<UserDTO> userList;

    public SaTokenInfo login(String username, String password) {
        UserDTO userDTO = loadUserByUsername(username);
        if (userDTO == null) return null;
        if (!SaSecureUtil.md5(password).equals(userDTO.getPassword())) return null;
        // Successful login
        StpUtil.login(userDTO.getId());
        StpUtil.getSession().set("userInfo", userDTO);
        return StpUtil.getTokenInfo();
    }
}

Note: Sa-Token’s session is a custom implementation, not the standard HttpSession.

micro-sa-token-api

Finally, create a protected API service that returns user information and a test endpoint requiring a specific permission.

Add the same Sa-Token and Redis dependencies to pom.xml.

Reuse the application.yml configuration.

User info endpoint:

@RestController
@RequestMapping("/user")
public class UserController {
    @GetMapping("/info")
    public CommonResult<UserDTO> userInfo() {
        UserDTO userDTO = (UserDTO) StpUtil.getSession().get("userInfo");
        return CommonResult.success(userDTO);
    }
}

Test endpoint requiring api:test:hello permission:

@RestController
@RequestMapping("/test")
public class TestController {
    @GetMapping("/hello")
    public CommonResult hello() {
        return CommonResult.success("Hello World.");
    }
}

Feature Demonstration

After starting Nacos and Redis, launch the three services (gateway, auth, API) in any order and use Postman to test the authentication flow.

Obtain a token by calling the login API through the gateway (e.g., http://localhost:9201/auth/user/login).

Access the protected /api/user/info endpoint without a token – request is denied.

Access the same endpoint with the token – request succeeds and returns user data.

Attempt to call the permission‑protected test endpoint as user macro – access is denied.

Switch to user admin (which has api:test:hello permission) and call the test endpoint – access succeeds.

Conclusion

Compared with a Spring Security‑based solution, Sa-Token offers a simpler and more elegant approach. With Spring Security you must configure authentication managers, handle unauthenticated and unauthorized responses, and set up separate resource server configurations, which is cumbersome. Sa-Token requires only a gateway filter for authentication/authorization and straightforward API calls for login and permission assignment.

References

Official documentation: http://sa-token.dev33.cn/

Source Code

GitHub repository: https://github.com/macrozheng/springcloud-learning/tree/master/micro-sa-token

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.

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