IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 一个注解搞定Spring Security 忽略拦截 -> 正文阅读

[Java知识库]一个注解搞定Spring Security 忽略拦截

/*
* Copyright 2021-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
  */

l

源码地址 galaxy-sea/galaxy-blogs/code/security-annotation

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(其实是我懒得写啦反正百度都有😄)
老规矩下面直接放代码吧。

代码就需要大家去start.spring.io生成一下啦,然后改一下Spring Boot的版本号,或者去我的GitHub直接clone代码: galaxy-sea/galaxy-blogs

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

总结

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

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-12-25 10:52:38  更:2022-12-25 10:54:43 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 7:34:03-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码