一个注解搞定 Spring Security 忽略拦截


prtyaa
prtyaa 2023-12-30 21:58:27 50019 赞同 0 反对 0
分类: 资源
Spring Security 拦截问题 一个注解搞定Spring Security 忽略拦截 基于注解形式 基于配置形式 总结

Spring Security 拦截问题

Spring Security是干啥的我就不想解释了, 毕竟百度上面的讲解一大堆解说的可是会比我细致 。

开发的时候我们经常需要对部分的@RequestMapping设置为 public api 不需要登陆也可以访问如登陆接口等等。偏爱Spring注解编程,那我们就基于注解的方式来忽略Spring Security的拦截吧。

public class SecurityConfigurer extends WebSecurityConfigurerAdapter {
  WebSecurity.IgnoredRequestConfigurer ignoring = web.ignoring();
     ignoring.antMatchers("/login");
     ignoring.antMatchers("/public api...");
}

就如我们上面代码展示的一样,我们经常需要对Spring Security的忽略名单进行硬编码配置或者配置文件配置我都感觉挺繁琐的,Spring都已经提倡基于注解编程了,百度到的内容居然还是教我用硬编码所以下面我们就机遇注解来实现Spring Security忽略拦截的实现吧。

一个注解搞定Spring Security 忽略拦截

本章节我们就用注解的方式来实现Spring Security忽略拦截吧。本章会分别介绍基于注解方式和配置文件方式

  • 注解主要针对@RequestMapping进行忽略
  • 配置文件主要针对静态文件(js,html,css,...)进行忽略
环境配置
  • Spring Boot 2.5.X
    • Spring MVC
    • Spring Security
    • lombok
  • Java 1.8
因为是单纯的演示一下如何基于注解忽略Spring Security拦截,所以只会使用最小demo而不是大篇长论的去魔改Spring Security(其实是我懒得写啦反正百度都有 )
老规矩下面直接放代码吧。

代码就需要大家去https://start.spring.io/生成一下啦,然后改一下Spring Boot的版本号,或者去我的GitHub直接clone代码,开头已经贴出!

SecurityConfiguration 配置类
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

  @Override
  public void configure(WebSecurity web) {
    WebSecurity.IgnoredRequestConfigurer ignoring = web.ignoring();
    ignoring.antMatchers(HttpMethod.GET, "/hello/hardcode");
  }
}
HelloController用于测试Spring Security拦截器
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author changjin wei(魏昌进)
 * @since 2022/12/15
 */
@RestController
@RequestMapping("hello")
public class HelloController {

  @GetMapping("/security")
  public String security(){
    return "Hello, Security";
  }

  @GetMapping("/hardcode")
  public String hardcode(){
    return "Hello, hardcode";
  }
}
测试结果
# 测试结果1
curl http://127.0.0.1:8080/hello/security -i
HTTP/1.1 401 
Content-Type: application/json

{"timestamp":"2022-12-16T10:54:44.403+00:00","status":401,"error":"Unauthorized","path":"/hello/security"}

# 测试结果2
curl http://127.0.0.1:8080/hello/hardcode -i
HTTP/1.1 200 
Content-Type: text/plain;charset=UTF-8

Hello, hardcod

基于注解形式

其实硬编码这种处理方式如果public api较少的情况下还是没有问题的,但是public api变多了就不是很友好了。

那么现在我们就基于注解的形式实现一下吧,代码量及其精简的哦。

首先我们创建一个IgnoreWebSecurity注解用户将api设置为public api, 然后我们改造一下SecurityConfiguration类。

IgnoreWebSecurity
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author changjin wei(魏昌进)
 * @since 2022/1/3
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface IgnoreWebSecurity {
}
改造 SecurityConfiguration
/**
 * @author changjin wei(魏昌进)
 * @since 2022/12/15
 */
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {


  private final RequestMappingHandlerMapping requestMappingHandlerMapping;


  @Override
  public void configure(WebSecurity web) {
    WebSecurity.IgnoredRequestConfigurer ignoring = web.ignoring();
    ignoring.antMatchers(HttpMethod.GET, "/hello/hardcode");
    this.ignoreAnnotation(ignoring, this.requestMappingHandlerMapping);
  }

  private void ignoreAnnotation(WebSecurity.IgnoredRequestConfigurer ignoring, RequestMappingHandlerMapping requestMappingHandlerMapping) {
    Map<RequestMappingInfo, HandlerMethod> handlerMethods = requestMappingHandlerMapping.getHandlerMethods();
    for (Map.Entry<RequestMappingInfo, HandlerMethod> entry : handlerMethods.entrySet()) {
      HandlerMethod handlerMethod = entry.getValue();
      if (handlerMethod.hasMethodAnnotation(IgnoreWebSecurity.class)) {
        Set<String> patternValues = entry.getKey().getPatternValues();
        Set<RequestMethod> methods = entry.getKey().getMethodsCondition().getMethods();
        if (CollectionUtils.isEmpty(methods)) {
          // RequestMapping没有指定method
          ignoring.antMatchers(patternValues.toArray(new String[0]));
        } else {
          for (RequestMethod method : methods) {
            // RequestMapping指定了method
            ignoring.antMatchers(HttpMethod.resolve(method.name()), patternValues.toArray(new String[0]));
          }
        }
      }
    }
  }
}
HelloController 增加一下测试方法
/**
 * @author changjin wei(魏昌进)
 * @since 2022/12/15
 */
@RestController
@RequestMapping("hello")
public class HelloController {

  /** 注解方式 */
  @GetMapping("/annotation")
  @IgnoreWebSecurity
  public String annotation() {
    return "Hello, annotation";
  }


  /** 测试PathVariable参数 */
  @GetMapping("/{path}/annotation")
  @IgnoreWebSecurity
  public String annotationPath(@PathVariable String path) {
    return "Hello, annotation. path: " + path;
  }
}
测试结果
# 测试注解
curl http://127.0.0.1:8080/hello/annotation -i
HTTP/1.1 200 
Content-Type: text/plain;charset=UTF-8
Content-Length: 17
Date: Sun, 18 Dec 2022 12:25:05 GMT

Hello, annotatio


# 测试注解
curl http://127.0.0.1:8080/hello/public_api/annotation -i
HTTP/1.1 200 
Content-Type: text/plain;charset=UTF-8
Content-Length: 35
Date: Sun, 18 Dec 2022 12:25:35 GMT

Hello, annotation. path: public_api

通过解析RequestMappingHandlerMapping我们就可以将api设置为public api了。这种方式大大简便的配置。

基于配置形式

上一章我们通过注解的方式去将api设置为public api但是这种方式对静态资源(html,js,css等)并不是很友好,好需要通过配置的文件的方式将一些静态资源设置为public,所以本章节通过配置文件方式来实现public api的忽略拦截

创建一个配置文件IgnoreWebSecurityProperties来配置

IgnoreWebSecurityProperties
/**
 * @author changjin wei(魏昌进)
 * @since 2022/12/15
 */
@Data
@ConfigurationProperties(prefix = "security.ignoring")
public class IgnoreWebSecurityProperties {
  /** 需要忽略的 URL 格式,不考虑请求方法 */
  private String[] pattern = {};

  /** 需要忽略的 GET 请求 */
  private String[] get = {};

  /**  需要忽略的 POST 请求 */
  private String[] post = {};

  /**  需要忽略的 DELETE 请求 */
  private String[] delete = {};

  /**  需要忽略的 PUT 请求 */
  private String[] put = {};

  /** 需要忽略的 HEAD 请求 */
  private String[] head = {};

  /** 需要忽略的 PATCH 请求 */
  private String[] patch = {};

  /** 需要忽略的 OPTIONS 请求 */
  private String[] options = {};

  /** 需要忽略的 TRACE 请求 */
  private String[] trace = {};
}
改造 IgnoreWebSecurityProperties
/**
 * @author changjin wei(魏昌进)
 * @since 2022/12/15
 */
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
@EnableConfigurationProperties(IgnoreWebSecurityProperties.class)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

  private final IgnoreWebSecurityProperties ignoreWebSecurityProperties;
  private final RequestMappingHandlerMapping requestMappingHandlerMapping;

  @Override
  public void configure(WebSecurity web) {
    WebSecurity.IgnoredRequestConfigurer ignoring = web.ignoring();
    ignoring.antMatchers(HttpMethod.GET, "/hello/hardcode");
    this.ignoreAnnotation(ignoring, this.requestMappingHandlerMapping);
    this.ignoreProperties(ignoring, this.ignoreWebSecurityProperties);
  }
    ...
  private void ignoreProperties(WebSecurity.IgnoredRequestConfigurer ignoring, IgnoreWebSecurityProperties ignoreWebSecurityProperties) {
    ignoring.antMatchers(HttpMethod.GET, ignoreWebSecurityProperties.getGet())
            .antMatchers(HttpMethod.POST, ignoreWebSecurityProperties.getPost())
            .antMatchers(HttpMethod.DELETE, ignoreWebSecurityProperties.getDelete())
            .antMatchers(HttpMethod.PUT, ignoreWebSecurityProperties.getPut())
            .antMatchers(HttpMethod.HEAD, ignoreWebSecurityProperties.getHead())
            .antMatchers(HttpMethod.PATCH, ignoreWebSecurityProperties.getPatch())
            .antMatchers(HttpMethod.OPTIONS, ignoreWebSecurityProperties.getOptions())
            .antMatchers(HttpMethod.TRACE, ignoreWebSecurityProperties.getTrace())
            .antMatchers(ignoreWebSecurityProperties.getPattern());
  }
}

改造HelloController
/**
 * @author changjin wei(魏昌进)
 * @since 2022/12/15
 */
@RestController
@RequestMapping("hello")
public class HelloController {
  /** 测试PathVariable参数 */
  @GetMapping("/properties")
  @IgnoreWebSecurity
  public String properties(){
    return "Hello, properties";
  }

  /** 测试PathVariable参数 */
  @GetMapping("/{path}/properties")
  @IgnoreWebSecurity
  public String propertiesPath(@PathVariable String path){
    return "Hello, properties. path: " + path;
  }
}
application.yml
security:
  ignoring:
    get:
      - /hello/{path}/properties
测试结果
# 配置文件测试
curl http://127.0.0.1:8080/hello/properties -i
HTTP/1.1 200 
Content-Type: text/plain;charset=UTF-8
Content-Length: 17
Date: Sun, 18 Dec 2022 12:35:14 GMT

Hello, properties

# 配置文件测试
curl http://127.0.0.1:8080/hello/public_api/properties -i
HTTP/1.1 200 
Content-Type: text/plain;charset=UTF-8
Content-Length: 35
Date: Sun, 18 Dec 2022 12:36:01 GMT

Hello, properties. path: public_api

总结

其实无论是介于注解方式还是配置文件方式都各有优缺点看大家是否的选择了,通过这种方式可以减少代码硬编码的问题。

如果您发现该资源为电子书等存在侵权的资源或对该资源描述不正确等,可点击“私信”按钮向作者进行反馈;如作者无回复可进行平台仲裁,我们会在第一时间进行处理!

评价 0 条
prtyaaL2
粉丝 1 资源 1949 + 关注 私信
最近热门资源
银河麒麟桌面操作系统备份用户数据  123
统信桌面专业版【全盘安装UOS系统】介绍  118
银河麒麟桌面操作系统安装佳能打印机驱动方法  109
银河麒麟桌面操作系统 V10-SP1用户密码修改  102
最近下载排行榜
银河麒麟桌面操作系统备份用户数据 0
统信桌面专业版【全盘安装UOS系统】介绍 0
银河麒麟桌面操作系统安装佳能打印机驱动方法 0
银河麒麟桌面操作系统 V10-SP1用户密码修改 0
作者收入月榜
1

prtyaa 收益393.62元

2

zlj141319 收益218元

3

1843880570 收益214.2元

4

IT-feng 收益209.03元

5

风晓 收益208.24元

6

777 收益172.71元

7

Fhawking 收益106.6元

8

信创来了 收益105.84元

9

克里斯蒂亚诺诺 收益91.08元

10

技术-小陈 收益79.5元

请使用微信扫码

加入交流群

请使用微信扫一扫!