在用Spring Security項目開發中,有時候需要放通某一個接口時,我們需要在配置中把接口地址配置上,這樣做有時候顯得麻煩,而且不夠優雅。我們能不能通過一個注解的方式,在需要放通的接口上加上該注解,這樣接口就能放通了。答案肯定是可以的啦,今天我們一起來看看實現過程吧。
1.SpringBoot版本
本文基于的Spring Boot的版本是2.6.7
2.實現思路
新建一個AnonymousAccess
注解,該注解是應用于Controller
方法上的
新建一個存放所有請求方式的枚舉類
通過判斷Controller
方法上是否存在該注解
在SecurityConfig
上進行策略的配置
3.實現過程
3.1新建注解
@Inherited
@Documented
@Target({ElementType.METHOD,ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface AnonymousAccess {
}
3.2新建請求枚舉類
該類是存放所有的請求類型的,代碼如下:
@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
的注解
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 類型。
@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上把需要的放通的接口上加上注解,即可不需要認證就可以訪問了,是不是很方便呢。例如,驗證碼不需要認證訪問的,代碼如下:
@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接口放通的資料請關注html5模板網其它相關文章!
【網站聲明】本站部分內容來源于互聯網,旨在幫助大家更快的解決問題,如果有圖片或者內容侵犯了您的權益,請聯系我們刪除處理,感謝您的支持!