Backend Development 9 min read

Implementing Distributed Authorization in Spring Cloud Microservices with Custom Annotations

This article explains how to shift authentication and authorization from the gateway to downstream Spring Cloud microservices by removing the gateway's ReactiveAuthorizationManager, defining three custom annotations (@RequiresLogin, @RequiresPermissions, @RequiresRoles), creating an AOP aspect to enforce them, and demonstrating their usage in controller methods.

Code Ape Tech Column
Code Ape Tech Column
Code Ape Tech Column
Implementing Distributed Authorization in Spring Cloud Microservices with Custom Annotations

The author revisits two common questions from readers of the "Spring Cloud Alibaba" video series: how to perform authorization inside each microservice and how to propagate authentication when using Feign calls.

Instead of handling authorization at the gateway, the article proposes delegating it to downstream services. The gateway configuration is simplified to permit all requests, while each service enforces its own security checks.

Step 1 – Remove the gateway authorization manager : The original gateway relied on ReactiveAuthorizationManager to validate every request. By deleting this manager and configuring the whitelist with .pathMatchers(...).permitAll() and .anyExchange().permitAll() , all traffic is forwarded directly to downstream services.

Step 2 – Define three custom annotations :

@RequiresLogin – ensures the user is logged in.

@RequiresPermissions – checks that the user possesses specific permission codes (supports AND/OR logic).

@RequiresRoles – verifies that the user has required role identifiers (also supports AND/OR).

Each annotation is declared with @Retention(RetentionPolicy.RUNTIME) and @Target({ElementType.METHOD, ElementType.TYPE}) . Example for @RequiresLogin :

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface RequiresLogin { }

Example for @RequiresPermissions (showing attributes for permission values and logical mode):

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface RequiresPermissions {
    String[] value() default {};
    Logical logical() default Logical.AND;
}

Example for @RequiresRoles (default roles are ROOT and ADMIN):

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface RequiresRoles {
    String[] value() default {OAuthConstant.ROLE_ROOT_CODE, OAuthConstant.ROLE_ADMIN_CODE};
    Logical logical() default Logical.AND;
}

Step 3 – Create an AOP aspect that intercepts any method annotated with the three custom annotations. The aspect extracts the method signature, checks for each annotation, and calls helper methods doCheckLogin() , doCheckRole() , and doCheckPermissions() . The role‑checking logic demonstrates both AND and OR matching against the user's authorities extracted from the token.

@Aspect
@Component
public class PreAuthorizeAspect {
    public static final String POINTCUT_SIGN = "@annotation(com.mugu.blog.common.annotation.RequiresLogin) || "
            + "@annotation(com.mugu.blog.common.annotation.RequiresPermissions) || "
            + "@annotation(com.mugu.blog.common.annotation.RequiresRoles)";

    @Pointcut(POINTCUT_SIGN)
    public void pointcut() {}

    @Around("pointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        checkMethodAnnotation(signature.getMethod());
        return joinPoint.proceed();
    }

    // helper methods omitted for brevity
}

Using the annotations is straightforward. For example, to restrict an article‑creation endpoint to administrators:

@RequiresRoles
@AvoidRepeatableCommit
@ApiOperation("Add Article")
@PostMapping("/add")
public ResultMsg
add(@RequestBody @Valid ArticleAddReq req) {
    // ...
}

The article also notes that Feign calls are treated like regular HTTP requests, so the same annotations work for remote service invocations. However, applying @RequiresRoles on a method that internally calls another service via Feign may cause authorization failures if the caller lacks the required role.

In conclusion, while delegating authorization to downstream services can solve specific use‑cases, the author recommends keeping authentication centralized at the gateway unless business requirements dictate otherwise.

BackendJavamicroservicesSpring Cloudauthorizationcustom annotations
Code Ape Tech Column
Written by

Code Ape Tech Column

Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn

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.