吊炸天,Spring Security还有这种用法!
在用Spring Security项目开发中,有时候需要放通某一个接口时,我们需要在配置中把接口地址配置上,这样做有时候显得麻烦,而且不够优雅。我们能不能通过一个注解的方式,在需要放通的接口上加上该注解,这样接口就能放通了。答案肯定是可以的啦,今天我们一起来看看实现过程吧。
SpringBoot版本
本文基于的Spring Boot的版本是2.6.7
实现思路
- 新建一个
AnonymousAccess
注解,该注解是应用于Controller
方法上的 - 新建一个存放所有请求方式的枚举类
- 通过判断
Controller
方法上是否存在该注解 - 在
SecurityConfig
上进行策略的配置
实现过程
新建注解
@Inherited
@Documented
@Target({ElementType.METHOD,ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface AnonymousAccess {
}
新建请求枚举类
该类是存放所有的请求类型的,代码如下:
@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;
}
}
判断Controller
方法上是否存在该注解
在SecurityConfig
类中定义一个私有方法getAnonymousUrl
,该方法主要作用是判断controller那些方法加上了AnonymousAccess
的注解
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;
}
在SecurityConfig
上进行策略的配置
通过一个SpringUtil
工具类获取到requestMappingHandlerMapping
的Bean
,然后通过getAnonymousUrl
方法把标注AnonymousAccess
接口找出来。最后,通过antMatchers
细腻化到每个 Request 类型。
@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();
}
在Controller方法上应用
在Controller上把需要的放通的接口上加上注解,即可不需要认证就可以访问了,是不是很方便呢。例如,验证码不需要认证访问的,代码如下:
@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;
}
效果展示
更多经常的内容请关注公众号"攻城狮成长日记"
吊炸天,Spring Security还有这种用法!的更多相关文章
- Spring Security 前后端分离登录,非法请求直接返回 JSON
hello 各位小伙伴,国庆节终于过完啦,松哥也回来啦,今天开始咱们继续发干货! 关于 Spring Security,松哥之前发过多篇文章和大家聊聊这个安全框架的使用: 手把手带你入门 Spring ...
- spring security 3中的10个典型用法小结
spring security 3比较庞大,但功能很强,下面小结下spring security 3中值得 注意的10个典型用法 1)多个authentication-provide可以同时使用 &l ...
- Spring Security笔记:Hello World
本文演示了Spring Security的最最基本用法,二个页面(或理解成二个url),一个需要登录认证后才能访问(比如:../admin/),一个可匿名访问(比如:../welcome) 注:以下内 ...
- Spring Security笔记:使用数据库进行用户认证(form login using database)
在前一节,学习了如何自定义登录页,但是用户名.密码仍然是配置在xml中的,这样显然太非主流,本节将学习如何把用户名/密码/角色存储在db中,通过db来实现用户认证 一.项目结构 与前面的示例相比,因为 ...
- 【JavaEE】SSH+Spring Security基础上配置AOP+log4j
Spring Oauth2大多数情况下还是用不到的,主要使用的还是Spring+SpringMVC+Hibernate,有时候加上SpringSecurity,因此,本文及以后的文章的example中 ...
- 使用 Spring Security 保护 Web 应用的安全
安全一直是 Web 应用开发中非常重要的一个方面.从安全的角度来说,需要考虑用户认证和授权两个方面.为 Web 应用增加安全方面的能力并非一件简单的事情,需要考虑不同的认证和授权机制.Spring S ...
- 【Spring】关于Boot应用中集成Spring Security你必须了解的那些事
Spring Security Spring Security是Spring社区的一个顶级项目,也是Spring Boot官方推荐使用的Security框架.除了常规的Authentication和A ...
- Spring Security(19)——对Acl的支持
目录 1.1 准备工作 1.2 表功能介绍 1.2.1 表acl_sid 1.2.2 表acl_class 1.2.3 表acl_obj ...
- Spring Security(18)——Jsp标签
目录 1.1 authorize 1.2 authentication 1.3 accesscontrollist Spring Security也有对Jsp标签的支持的标签库 ...
随机推荐
- POJ 2236:Wireless Network
描述 n台电脑,如果两台电脑间的距离的d范围内,则两台电脑能够连通. 如果AB连通,BC连通,则认为AC连通. 已知电脑台数N,最大距离d,以及每个电脑的坐标.有如下两种操作: O i 表示修复编号为 ...
- 二十二、导入DXF文件
x
- 开关电源PCB排版,基本要点分析
1 开关电源PCB排版基本要点 1.1 电容高频滤波特性 图1是电容器基本结构和高频等效模型. 电容的基本公式是 式(1)显示,减小电容器极板之间的距离(d)和增加极板的截面积(A)将增加电容器的电容 ...
- Hive进行数据统计时报错:org.apache.hadoop.mapreduce.v2.app.MRAppMaster: Error starting MRAppMaster
报错详情: 2020-04-09 22:56:58,827 ERROR [Listener at 0.0.0.0/45871] org.apache.hadoop.mapreduce.v2.app.M ...
- java中单态模式或单例模式(Singleton)有什么意义?
8.单态模式或单例模式(Singleton) 单态模式有什么用呢?想一下Adobe Photoshop ,处理两张图,会启动两个photoshop吗?多耗费内存呀! ( Consider Adobe ...
- CCF201503-1图像旋转
问题描述 旋转是图像处理的基本操作,在这个问题中,你需要将一个图像逆时针旋转90度. 计算机中的图像表示可以用一个矩阵来表示,为了旋转一个图像,只需要将对应的矩阵旋转即可. 输入格式 输入的第一行包含 ...
- localStorage存储返回过来的对象 显示object object的问题
localStorage.setItem() 不会自动将Json对象转成字符串形式 用localStorage.setItem()正确存储JSON对象方法是: 存储前先用JSON.stringify( ...
- Element instanceof Node
今天看到一个问题,问 Element instance Node 为什么是 false. 首先,我们知道 Element 是 Node 的子类,那么为什么 Element instanceof Nod ...
- Redis4.0.14 迁槽失败
线上一个redis集群中主节点使用的内存达到了9.78g,按照redis单个实例最大内存不要超出10g的规范,扩容操作就放在了今天晚上进行.因为之前redis迁槽都是采用 redis-trib.rb ...
- 基于Vue的v-charts导出图片并下载
依赖 npm install file-saver 页面 <ve-chart ref="chart"></ve-chart> <el-button t ...