当前位置:网站首页>Three annotations, elegant implementation of micro service authentication

Three annotations, elegant implementation of micro service authentication

2022-06-09 18:33:00 Not just Chen

Hello everyone , I'm not just Chen ~

This is a 《Spring Cloud Advanced 》 The first 39 An article , The previous article introduced gateway integration Spring Security Realize unified authentication at the gateway level .

If there is something unclear, you can read the previous article : Combat dry goods !Spring Cloud Gateway Integrate OAuth2.0 Realize distributed unified authentication and authorization !

Recently subscribed to 《Spring Cloud Alibaba actual combat 》 Readers of the video column often ask Chen two questions , as follows :

  1. How to do authentication in each micro service ?

  2. feign How to do authentication by calling ?

Today, let's talk about how to solve the above two problems through three annotations .

Digression : Chen will be in B standing 、 Share some video tutorials in official account , After all, the article is difficult to understand .

B Station links :https://b23.tv/wdfX4E6

Below is a video tutorial for this article , Explain in more detail !726a28d70cf7b4bb3cd8adb8b1b29803.gif

The handsome people all praised ~

Realize the idea

In the previous articles, Mr. Chen unified authentication and authentication at the gateway level , The structure is as follows :

324ad306a642e7c6414b977f1e96b554.png

There is another way of thinking about authentication in microservices : Give the authentication to the downstream microservices , The gateway layer only does routing forwarding .

This idea is actually very simple to realize , The following code transformation for authentication at the gateway level can be completed : Combat dry goods !Spring Cloud Gateway Integrate OAuth2.0 Realize distributed unified authentication and authorization !

1. Kill the authentication manager

Unified authentication at the gateway is actually a dependent authentication manager ReactiveAuthorizationManager, All requests need to be authenticated by the authentication manager to authenticate the login user's permission .

This authentication manager is also introduced in the article on gateway authentication , In Chen's 《Spring Cloud Alibaba actual combat 》 It is also easy to configure interception in , as follows :

b5f30aae31191f4904a657b670fadcb2.png

In addition to the configured white list , All other requests must be intercepted and authenticated by the authentication manager of the gateway , Only after authentication can the route be released and forwarded to the downstream service .

Is it clear to see the train of thought here , You want to give authentication to downstream services , It only needs to be released directly at the gateway level , Do not use the authentication manager , The code is as follows :

http
 ....
 // White list direct release 
  .pathMatchers(ArrayUtil.toArray(whiteUrls.getUrls(), String.class)).permitAll()
 // Any other request for direct release 
  .anyExchange().permitAll()
  .....

2. Define three annotations

After the first ① Step , Authentication has been delegated to downstream services , So how do downstream services intercept and authenticate ?

Actually Spring Security Provides 3 Annotations are used to control permissions , as follows :

  1. @Secured

  2. @PreAuthorize

  3. @PostAuthorize

These three notes will not be introduced in detail , If you are interested, you can consult the official documents .

Chen doesn't plan to use the three built-in annotations to realize , Instead, three annotations are customized , as follows :

[email protected]

See the name and know the meaning , Only when the user logs in can it be released , The code is as follows :

/**
 * @author  official account : Code ape technology column 
 * @url: www.java-family.cn
 * @description  Notes for login authentication , Marked on controller On the way , Must be a login to access the interface 
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface RequiresLogin {
}

[email protected]

See the name and know the meaning , Only those with the specified authority can be released , The code is as follows :

/**
 * @author  official account : Code ape technology column 
 * @url: www.java-family.cn
 * @description  Marked on controller On the way , Ensure that you have the specified permissions to access the interface 
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface RequiresPermissions {
    /**
     *  Permission code to be verified 
     */
    String[] value() default {};

    /**
     *  Verification mode :AND | OR, Default AND
     */
    Logical logical() default Logical.AND;
}

[email protected]

See the name and know the meaning , Only the specified role can be released , The code is as follows :

/**
 * @author  official account : Code ape technology column 
 * @url: www.java-family.cn
 * @description  Marked on controller On the way , Ensure that you have the specified role to access the interface 
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface RequiresRoles {
    /**
     *  Role ID to be verified , Default override and Administrator 
     */
    String[] value() default {OAuthConstant.ROLE_ROOT_CODE,OAuthConstant.ROLE_ADMIN_CODE};

    /**
     *  Verification logic :AND | OR, Default AND
     */
    Logical logical() default Logical.AND;
}

The meaning of the above three notes must be well understood , No more explanation here ....

3. Annotation facet definition

The annotation has , So how to intercept ? Here, Chen defines an aspect to intercept , The key codes are as follows :

/**
 * @author  official account : Code ape technology column 
 * @url: www.java-family.cn
 * @description @RequiresLogin,@RequiresPermissions,@RequiresRoles  Section of annotation 
 */
@Aspect
@Component
public class PreAuthorizeAspect {
    /**
     *  structure 
     */
    public PreAuthorizeAspect() {
    }

    /**
     *  Definition AOP Signature  ( Cut into all methods that use authentication annotations )
     */
    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)";

    /**
     *  Statement AOP Signature 
     */
    @Pointcut(POINTCUT_SIGN)
    public void pointcut() {
    }

    /**
     *  Circle cut 
     *
     * @param joinPoint  Tangent object 
     * @return  The return value of the underlying method after execution 
     * @throws Throwable  Exceptions thrown by the underlying method 
     */
    @Around("pointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        //  Annotation authentication 
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        checkMethodAnnotation(signature.getMethod());
        try {
            //  Execute the original logic 
            Object obj = joinPoint.proceed();
            return obj;
        } catch (Throwable e) {
            throw e;
        }
    }

    /**
     *  To a Method Object for annotation checking 
     */
    public void checkMethodAnnotation(Method method) {
        //  check  @RequiresLogin  annotation 
        RequiresLogin requiresLogin = method.getAnnotation(RequiresLogin.class);
        if (requiresLogin != null) {
            doCheckLogin();
        }

        //  check  @RequiresRoles  annotation 
        RequiresRoles requiresRoles = method.getAnnotation(RequiresRoles.class);
        if (requiresRoles != null) {
            doCheckRole(requiresRoles);
        }

        //  check  @RequiresPermissions  annotation 
        RequiresPermissions requiresPermissions = method.getAnnotation(RequiresPermissions.class);
        if (requiresPermissions != null) {
            doCheckPermissions(requiresPermissions);
        }
    }


    /**
     *  Verify whether there is login 
     */
    private void doCheckLogin() {
        LoginVal loginVal = SecurityContextHolder.get();
        if (Objects.isNull(loginVal))
            throw new ServiceException(ResultCode.INVALID_TOKEN.getCode(), ResultCode.INVALID_TOKEN.getMsg());
    }

    /**
     *  Verify whether there is a corresponding role 
     */
    private void doCheckRole(RequiresRoles requiresRoles){
        String[] roles = requiresRoles.value();
        LoginVal loginVal = OauthUtils.getCurrentUser();

        // The corresponding role of the login user 
        String[] authorities = loginVal.getAuthorities();
        boolean match=false;

        //and  Logic 
        if (requiresRoles.logical()==Logical.AND){
            match = Arrays.stream(authorities).filter(StrUtil::isNotBlank).allMatch(item -> CollectionUtil.contains(Arrays.asList(roles), item));
        }else{  //OR  Logic 
            match = Arrays.stream(authorities).filter(StrUtil::isNotBlank).anyMatch(item -> CollectionUtil.contains(Arrays.asList(roles), item));
        }

        if (!match)
            throw new ServiceException(ResultCode.NO_PERMISSION.getCode(), ResultCode.NO_PERMISSION.getMsg());
    }

    /**
     * TODO  Realize it by yourself , Because the front-end menu permissions are not integrated , Implement by yourself according to business requirements 
     */
    private void doCheckPermissions(RequiresPermissions requiresPermissions){

    }
}

In fact, the logic is very simple , It's analytic Token The permissions 、 The role is then compared with the one specified in the annotation .

@RequiresPermissions The logic of this annotation has not been realized by Chen , Imitate and complete according to the business , It's a thinking problem ....

4. Annotations use

such as 《Spring Cloud Alibaba actual combat 》 There is an interface to add articles in the project , Only the roles of supervisor and administrator can be added , Then you can use @RequiresRoles Annotate , as follows :

@RequiresRoles
@AvoidRepeatableCommit
@ApiOperation(" Add the article ")
@PostMapping("/add")
public ResultMsg<Void> add(@RequestBody @Valid ArticleAddReq req){
 .......
}

The effect will not be demonstrated here , The actual effect : Non hypervisor and administrator role users log in and access , Will be directly blocked , Return no permission .

Be careful : This only solves the problem of downstream service authentication , that feign Whether the call also applies ?

Of course , Here we use the section method ,feign In fact, what we use inside is http Way to call , The same applies to interfaces .

such as 《Spring Cloud Alibaba actual combat 》 The interface to get the list of articles in the project , It will pass feign Call the interface in the comment service to get the total number of article comments , Once you add @RequiresRoles, Then the call will fail , The code is as follows :

@RequiresRoles
@ApiOperation(value = " Total number of articles obtained in batch ")
@PostMapping(value = "/list/total")
public ResultMsg<List<TotalVo>> listTotal(@RequestBody @Valid List<CommentListReq> param){
....
}

summary

This article mainly introduces how to delegate authentication to microservices , It is also to solve the readers' doubts , In actual production, unless the business needs , Chen still suggests that authentication be unified in the gateway .

And finally ( Don't whore for nothing , Please pay attention to )

Chen's every article is carefully output , Has written 3 A column , Put it in order PDF, Here's how to get it :

  1. 《Spring Cloud Advanced 》PDF: Official account :【 Code ape technology column 】 Reply key words Spring Cloud Advanced obtain !

  2. 《Spring Boot Advanced 》PDF: Official account :【 Code ape technology column 】 Reply key words Spring Boot Advanced obtain !

  3. 《Mybatis Advanced 》PDF: Official account :【 Code ape technology column 】 Reply key words Mybatis Advanced obtain !

If this article helps you , Or if there's some inspiration , Give me a favor 、 Looking at 、 forward 、 Collection , Your support is the biggest driving force for me to persevere !

Handsome people are praising 、 Share 、 Looking at San Lian e2d404dffa1f09f5a2c056442e2f274c.png

原网站

版权声明
本文为[Not just Chen]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/160/202206091826363941.html