好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

Spring Security实现接口放通的方法详解

在用Spring Security项目开发中,有时候需要放通某一个接口时,我们需要在配置中把接口地址配置上,这样做有时候显得麻烦,而且不够优雅。我们能不能通过一个注解的方式,在需要放通的接口上加上该注解,这样接口就能放通了。答案肯定是可以的啦,今天我们一起来看看实现过程吧。

1.SpringBoot版本

本文基于的Spring Boot的版本是2.6.7

2.实现思路

新建一个 AnonymousAccess 注解,该注解是应用于 Controller 方法上的

新建一个存放所有请求方式的枚举类

通过判断 Controller 方法上是否存在该注解

在 SecurityConfig 上进行策略的配置

3.实现过程

3.1新建注解

?

1

2

3

4

5

6

7

@Inherited

@Documented

@Target ({ElementType.METHOD,ElementType.ANNOTATION_TYPE})

@Retention (RetentionPolicy.RUNTIME)

public @interface AnonymousAccess {

    

}

3.2新建请求枚举类

该类是存放所有的请求类型的,代码如下:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

@Getter

@AllArgsConstructor

public enum RequestMethodEnum {

     /**

      * 搜寻 @AnonymousGetMapping

      */

     GET( "GET" ),

 

     /**

      * 搜寻 @AnonymousPostMapping

      */

     POST( "POST" ),

 

     /**

      * 搜寻 @AnonymousPutMapping

      */

     PUT( "PUT" ),

 

     /**

      * 搜寻 @AnonymousPatchMapping

      */

     PATCH( "PATCH" ),

 

     /**

      * 搜寻 @AnonymousDeleteMapping

      */

     DELETE( "DELETE" ),

 

     /**

      * 否则就是所有 Request 接口都放行

      */

     ALL( "All" );

 

     /**

      * Request 类型

      */

     private final String type;

 

     public static RequestMethodEnum find(String type) {

         for (RequestMethodEnum value : RequestMethodEnum.values()) {

             if (value.getType().equals(type)) {

                 return value;

             }

         }

         return ALL;

     }

}

3.3判断Controller方法上是否存在该注解

在 SecurityConfig 类中定义一个私有方法 getAnonymousUrl ,该方法主要作用是判断controller那些方法加上了 AnonymousAccess 的注解

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

private Map<String, Set<String>> getAnonymousUrl(Map<RequestMappingInfo, HandlerMethod> handlerMethodMap) {

     Map<String, Set<String>> anonymousUrls = new HashMap<>( 8 );

     Set<String> get = new HashSet<>();

     Set<String> post = new HashSet<>();

     Set<String> put = new HashSet<>();

     Set<String> patch = new HashSet<>();

     Set<String> delete = new HashSet<>();

     Set<String> all = new HashSet<>();

     for (Map.Entry<RequestMappingInfo, HandlerMethod> infoEntry : handlerMethodMap.entrySet()) {

 

         HandlerMethod handlerMethod = infoEntry.getValue();

         AnonymousAccess anonymousAccess = handlerMethod.getMethodAnnotation(AnonymousAccess. class );

         if ( null != anonymousAccess) {

             List<RequestMethod> requestMethods = new ArrayList<>(infoEntry.getKey().getMethodsCondition().getMethods());

             RequestMethodEnum request = RequestMethodEnum.find(requestMethods.size() == 0 ? RequestMethodEnum.ALL.getType() : requestMethods.get( 0 ).name());

             switch (Objects.requireNonNull(request)) {

                 case GET:

                     get.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());

                     break ;

                 case POST:

                     post.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());

                     break ;

                 case PUT:

                     put.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());

                     break ;

                 case PATCH:

                     patch.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());

                     break ;

                 case DELETE:

                     delete.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());

                     break ;

                 default :

                     all.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());

                     break ;

             }

         }

     }

     anonymousUrls.put(RequestMethodEnum.GET.getType(), get);

     anonymousUrls.put(RequestMethodEnum.POST.getType(), post);

     anonymousUrls.put(RequestMethodEnum.PUT.getType(), put);

     anonymousUrls.put(RequestMethodEnum.PATCH.getType(), patch);

     anonymousUrls.put(RequestMethodEnum.DELETE.getType(), delete);

     anonymousUrls.put(RequestMethodEnum.ALL.getType(), all);

     return anonymousUrls;

}

3.4在SecurityConfig上进行策略的配置

通过一个 SpringUtil 工具类获取到 requestMappingHandlerMapping 的 Bean ,然后通过 getAnonymousUrl 方法把标注 AnonymousAccess 接口找出来。最后,通过 antMatchers 细腻化到每个 Request 类型。

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

@Override

protected void configure(HttpSecurity httpSecurity) throws Exception {

     // 搜寻匿名标记 url: @AnonymousAccess

     RequestMappingHandlerMapping requestMappingHandlerMapping = (RequestMappingHandlerMapping) SpringUtil.getBean( "requestMappingHandlerMapping" );

     Map<RequestMappingInfo, HandlerMethod> handlerMethodMap = requestMappingHandlerMapping.getHandlerMethods();

     // 获取匿名标记

     Map<String, Set<String>> anonymousUrls = getAnonymousUrl(handlerMethodMap);

     httpSecurity

             //禁用CSRF

             .csrf().disable()

             .authorizeRequests()

             // 自定义匿名访问所有url放行:细腻化到每个 Request 类型

             // GET

             .antMatchers(HttpMethod.GET,anonymousUrls.get(RequestMethodEnum.GET.getType()).toArray( new String[ 0 ])).permitAll()

             // POST

             .antMatchers(HttpMethod.POST,anonymousUrls.get(RequestMethodEnum.POST.getType()).toArray( new String[ 0 ])).permitAll()

             // PUT

             .antMatchers(HttpMethod.PUT,anonymousUrls.get(RequestMethodEnum.PUT.getType()).toArray( new String[ 0 ])).permitAll()

             // PATCH

             .antMatchers(HttpMethod.PATCH,anonymousUrls.get(RequestMethodEnum.PATCH.getType()).toArray( new String[ 0 ])).permitAll()

             // DELETE

             .antMatchers(HttpMethod.DELETE,anonymousUrls.get(RequestMethodEnum.DELETE.getType()).toArray( new String[ 0 ])).permitAll()

             // 所有类型的接口都放行

             .antMatchers(anonymousUrls.get(RequestMethodEnum.ALL.getType()).toArray( new String[ 0 ])).permitAll()

             // 所有请求都需要认证

             .anyRequest().authenticated();

    

}

3.5在Controller方法上应用

在Controller上把需要的放通的接口上加上注解,即可不需要认证就可以访问了,是不是很方便呢。例如,验证码不需要认证访问的,代码如下:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

@ApiOperation (value = "获取验证码" , notes = "获取验证码" )

@AnonymousAccess

@GetMapping ( "/code" )

public Object getCode(){

 

     Captcha captcha = loginProperties.getCaptcha();

     String uuid = "code-key-" +IdUtil.simpleUUID();

     //当验证码类型为 arithmetic时且长度 >= 2 时,captcha.text()的结果有几率为浮点型

     String captchaValue = captcha.text();

     if (captcha.getCharType()- 1 == LoginCodeEnum.ARITHMETIC.ordinal() && captchaValue.contains( "." )){

         captchaValue = captchaValue.split( "\\." )[ 0 ];

     }

     // 保存

     redisUtils.set(uuid,captchaValue,loginProperties.getLoginCode().getExpiration(), TimeUnit.MINUTES);

     // 验证码信息

     Map<String,Object> imgResult = new HashMap<String,Object>( 2 ){{

         put( "img" ,captcha.toBase64());

         put( "uuid" ,uuid);

     }};

     return imgResult;

 

}

3.6效果展示

以上就是Spring Security实现接口放通的方法详解的详细内容,更多关于Spring Security接口放通的资料请关注其它相关文章!

原文链接:https://www.cnblogs.com/alanlin/p/16291601.html

查看更多关于Spring Security实现接口放通的方法详解的详细内容...

  阅读:20次