色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

如何通過自定義注解進行接口匿名訪問

Android編程精選 ? 來源:CSDN技術社區 ? 作者:HUWD ? 2022-03-15 14:37 ? 次閱讀

在實際項目中使用到了springsecurity作為安全框架,我們會遇到需要放行一些接口,使其能匿名訪問的業務需求。但是每當需要當需要放行時,都需要在security的配置類中進行修改,感覺非常的不優雅。

例如這樣:

0e468b82-9475-11ec-952b-dac502259ad0.png

所以想通過自定義一個注解,來進行接口匿名訪問。在實現需求前,我們先了解一下security的兩種方行思路。

第一種就是在configure(WebSecurity web)方法中配置放行,像下面這樣:

@Overridepublicvoidconfigure(WebSecurityweb)throwsException{
web.ignoring().antMatchers("/css/**","/js/**","/index.html","/img/**","/fonts/**","/favicon.ico","/verifyCode");
}

第二種方式是在configure(HttpSecurity http)方法中進行配置:

@Overrideprotectedvoidconfigure(HttpSecurityhttpSecurity)throwsException
{
httpSecurity
.authorizeRequests()
.antMatchers("/hello").permitAll()
.anyRequest().authenticated()
}

兩種方式最大的區別在于,第一種方式是不走 Spring Security 過濾器鏈,而第二種方式走 Spring Security 過濾器鏈,在過濾器鏈中,給請求放行。

在我們使用 Spring Security 的時候,有的資源可以使用第一種方式額外放行,不需要驗證,例如前端頁面的靜態資源,就可以按照第一種方式配置放行。

有的資源放行,則必須使用第二種方式,例如登錄接口。大家知道,登錄接口也是必須要暴露出來的,不需要登錄就能訪問到的,但是我們卻不能將登錄接口用第一種方式暴露出來,登錄請求必須要走 Spring Security 過濾器鏈,因為在這個過程中,還有其他事情要做,具體的登錄流程想了解的可以自行百度。

了解完了security的兩種放行策略后,我們開始實現

首先創建一個自定義注解

@Target({ElementType.METHOD})//注解放置的目標位置,METHOD是可注解在方法級別上@Retention(RetentionPolicy.RUNTIME)//注解在哪個階段執行@Documented//生成文檔public@interfaceIgnoreAuth{
}

這里說明一下,@Target({ElementType.METHOD})我的實現方式,注解只能標記在帶有@RequestMapping注解的方法上。具體為什么下面的實現方式看完就懂了。

接下來創建一個security的配置類SecurityConfig并繼承WebSecurityConfigurerAdapter

@EnableGlobalMethodSecurity(prePostEnabled=true,securedEnabled=true)
publicclassSecurityConfigextendsWebSecurityConfigurerAdapter
{

@Autowired
privateRequestMappingHandlerMappingrequestMappingHandlerMapping;

/**
*@description:使用這種方式放行的接口,不走SpringSecurity過濾器鏈,
*無法通過SecurityContextHolder獲取到登錄用戶信息的,
*因為它一開始沒經過 SecurityContextPersistenceFilter 過濾器鏈。
*@dateTime:2021/7/1910:22
*/
@Override
publicvoidconfigure(WebSecurityweb)throwsException{
WebSecurityand=web.ignoring().and();
MaphandlerMethods=requestMappingHandlerMapping.getHandlerMethods();
handlerMethods.forEach((info,method)->{
//帶IgnoreAuth注解的方法直接放行
if(StringUtils.isNotNull(method.getMethodAnnotation(IgnoreAuth.class))){
//根據請求類型做不同的處理
info.getMethodsCondition().getMethods().forEach(requestMethod->{
switch(requestMethod){
caseGET:
//getPatternsCondition得到請求url數組,遍歷處理
info.getPatternsCondition().getPatterns().forEach(pattern->{
//放行
and.ignoring().antMatchers(HttpMethod.GET,pattern);
});
break;
casePOST:
info.getPatternsCondition().getPatterns().forEach(pattern->{
and.ignoring().antMatchers(HttpMethod.POST,pattern);
});
break;
caseDELETE:
info.getPatternsCondition().getPatterns().forEach(pattern->{
and.ignoring().antMatchers(HttpMethod.DELETE,pattern);
});
break;
casePUT:
info.getPatternsCondition().getPatterns().forEach(pattern->{
and.ignoring().antMatchers(HttpMethod.PUT,pattern);
});
break;
default:
break;
}
});
}
});
}
}

在這里使用Spring為我們提供的RequestMappingHandlerMapping類,我們可以通過requestMappingHandlerMapping.getHandlerMethods();獲取到所有的RequestMappingInfo信息。

以下是源碼部分,可不看,看了可以加深理解

這里簡單說一下RequestMappingHandlerMapping的工作流程,便于理解。我們通過翻看源碼

0e5acca0-9475-11ec-952b-dac502259ad0.png

繼承關系如上圖所示。

AbstractHandlerMethodMapping實現了InitializingBean接口

publicinterfaceInitializingBean{
voidafterPropertiesSet()throwsException;
}

AbstractHandlerMethodMapping類中通過afterPropertiesSet方法調用initHandlerMethods進行初始化

publicvoidafterPropertiesSet(){
this.initHandlerMethods();
}

protectedvoidinitHandlerMethods(){
String[]var1=this.getCandidateBeanNames();
intvar2=var1.length;

for(intvar3=0;var3if(!beanName.startsWith("scopedTarget.")){
this.processCandidateBean(beanName);
}
}

this.handlerMethodsInitialized(this.getHandlerMethods());
}

再調用processCandidateBean方法:

protectedvoidprocessCandidateBean(StringbeanName){
ClassbeanType=null;

try{
beanType=this.obtainApplicationContext().getType(beanName);
}catch(Throwablevar4){
if(this.logger.isTraceEnabled()){
this.logger.trace("Couldnotresolvetypeforbean'"+beanName+"'",var4);
}
}

if(beanType!=null&&this.isHandler(beanType)){
this.detectHandlerMethods(beanName);
}

}

通過調用方法中的isHandler方法是不是requestHandler方法,可以看到源碼是通過RequestMapping,Controller 注解進行判斷的。

protectedbooleanisHandler(ClassbeanType){
returnAnnotatedElementUtils.hasAnnotation(beanType,Controller.class)||AnnotatedElementUtils.hasAnnotation(beanType,RequestMapping.class);
}

判斷通過后,調用detectHandlerMethods方法將handler注冊到HandlerMethod的緩存中。

protectedvoiddetectHandlerMethods(Objecthandler){
ClasshandlerType=handlerinstanceofString?this.obtainApplicationContext().getType((String)handler):handler.getClass();
if(handlerType!=null){
ClassuserType=ClassUtils.getUserClass(handlerType);
Mapmethods=MethodIntrospector.selectMethods(userType,(method)->{
try{
returnthis.getMappingForMethod(method,userType);
}catch(Throwablevar4){
thrownewIllegalStateException("Invalidmappingonhandlerclass["+userType.getName()+"]:"+method,var4);
}
});
if(this.logger.isTraceEnabled()){
this.logger.trace(this.formatMappings(userType,methods));
}

methods.forEach((method,mapping)->{
MethodinvocableMethod=AopUtils.selectInvocableMethod(method,userType);
this.registerHandlerMethod(handler,invocableMethod,mapping);
});
}

}

通過registerHandlerMethod方法將handler放到private final Map mappingLookup = new LinkedHashMap();map中。

requestMappingHandlerMapping.getHandlerMethods()方法就是獲取所有的HandlerMapping。

publicMapgetHandlerMethods(){
this.mappingRegistry.acquireReadLock();

Mapvar1;
try{
var1=Collections.unmodifiableMap(this.mappingRegistry.getMappings());
}finally{
this.mappingRegistry.releaseReadLock();
}

returnvar1;
}

最后就是對map進行遍歷,判斷是否帶有IgnoreAuth.class注解,然后針對不同的請求方式進行放行。

handlerMethods.forEach((info,method)->{
//帶IgnoreAuth注解的方法直接放行
if(StringUtils.isNotNull(method.getMethodAnnotation(IgnoreAuth.class))){
//根據請求類型做不同的處理
info.getMethodsCondition().getMethods().forEach(requestMethod->{
switch(requestMethod){
caseGET:
//getPatternsCondition得到請求url數組,遍歷處理
info.getPatternsCondition().getPatterns().forEach(pattern->{
//放行
and.ignoring().antMatchers(HttpMethod.GET,pattern);
});
break;
casePOST:
info.getPatternsCondition().getPatterns().forEach(pattern->{
and.ignoring().antMatchers(HttpMethod.POST,pattern);
});
break;
caseDELETE:
info.getPatternsCondition().getPatterns().forEach(pattern->{
and.ignoring().antMatchers(HttpMethod.DELETE,pattern);
});
break;
casePUT:
info.getPatternsCondition().getPatterns().forEach(pattern->{
and.ignoring().antMatchers(HttpMethod.PUT,pattern);
});
break;
default:
break;
}
});
}
});

看到這里就能理解我最開始的強調的需標記在帶有@RequestMapping注解的方法上。我這里使用到的是configure(WebSecurity web)的放行方式。它是不走security的過濾鏈,是無法通過SecurityContextHolder獲取到登錄用戶信息的,這點問題是需要注意的。

審核編輯:郭婷


聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 接口
    +關注

    關注

    33

    文章

    8575

    瀏覽量

    151015

原文標題:如何利用自定義注解放行 Spring Security 項目的接口

文章出處:【微信號:AndroidPush,微信公眾號:Android編程精選】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    Springboot是如何獲取自定義異常并進行返回的

    這里看到新服務是封裝的自定義異常,準備入手剖析一下,自定義的異常是如何進行抓住我們請求的方法的異常,并進行封裝返回到。廢話不多說,先看看如何才能實現封裝異常,先來一個示例:在這里,您會
    發表于 03-22 14:15

    1602自定義字符

    1602液晶能夠顯示自定義字符,能夠根據讀者的具體情況顯示自定義字符。
    發表于 01-20 15:43 ?1次下載

    自定義fifo接口控制器

    自定義fifo接口控制器,利用sopc builder實現。
    發表于 03-22 14:09 ?1次下載

    使用Spring自定義注解的實現

    執行器。其本質就是通過外部參數進行一次路由和Spring mvc做的事情類似。簡單看了Spring mvc的實現原理之后,決定使用自定義注解的方式來實現以上功能。
    發表于 09-28 11:55 ?0次下載

    AN958:自定義設計的調試和編程接口

    包含調試和編程接口連接器。可能的選項有全面支持STK的所有調試和編程功能,僅限串行線編程。本應用說明介紹了在自定義硬件設計中包括這些連接器接口的優點,并提供了有關這些接口的詳細信息。
    發表于 02-28 15:14 ?2次下載

    自定義sobel濾波IP核,IP接口遵守AXI Stream協議

    自定義sobel濾波IP核 IP接口遵守AXI Stream協議
    的頭像 發表于 08-06 06:04 ?3911次閱讀

    如何通過LUA實現自定義串口指令設置

    本章節主要講述通過 LUA 實現自定義串口指令設置按鈕按下、設置文本、設置蜂鳴器響。并在按下按鈕或通過鍵盤輸入數據后發送自定義指令。本文將分為以下是 4 個階段講述教程 DEMO 是如
    發表于 10-17 08:00 ?8次下載
    如何<b class='flag-5'>通過</b>LUA實現<b class='flag-5'>自定義</b>串口指令設置

    C#與STM32自定義通信協議

    C#與STM32自定義通信協議功能:1.可通過C#上位機對多臺STM32下位機進行控制2.自定義上位機與下位機通信協議
    發表于 12-24 18:59 ?37次下載
    C#與STM32<b class='flag-5'>自定義</b>通信協議

    自定義視圖組件教程案例

    自定義組件 1.自定義組件-particles(粒子效果) 2.自定義組件- pulse(脈沖button效果) 3.自定義組件-progress(progress效果) 4.
    發表于 04-08 10:48 ?14次下載

    ArkUI如何自定義彈窗(eTS)

    自定義彈窗其實也是比較簡單的,通過CustomDialogController類就可以顯示自定義彈窗。
    的頭像 發表于 08-31 08:24 ?2189次閱讀

    labview自定義控件

    labview自定義精美控件
    發表于 05-15 16:46 ?17次下載

    自定義算子開發

    一個完整的自定義算子應用過程包括注冊算子、算子實現、含自定義算子模型轉換和運行含自定義op模型四個階段。在大多數情況下,您的模型應該可以通過使用hb_mapper工具完成轉換并順利部署
    的頭像 發表于 04-07 16:11 ?2794次閱讀
    <b class='flag-5'>自定義</b>算子開發

    自定義AXI-Lite接口的IP及源碼分析

    在 Vivado 中自定義 AXI4-Lite 接口的 IP,實現一個簡單的 LED 控制功能,并將其掛載到 AXI Interconnect 總線互聯結構上,通過 ZYNQ 主機控制,后面對 Xilinx 提供的整個 AXI4
    發表于 06-25 16:31 ?3326次閱讀
    <b class='flag-5'>自定義</b>AXI-Lite<b class='flag-5'>接口</b>的IP及源碼分析

    labview超快自定義控件制作和普通自定義控件制作

    labview超快自定義控件制作和普通自定義控件制作
    發表于 08-21 10:32 ?13次下載

    TSMaster 自定義 LIN 調度表編程指導

    LIN(LocalInterconnectNetwork)協議調度表是用于LIN總線通信中的消息調度的一種機制,我們收到越來越多來自不同用戶希望能夠通過接口實現自定義LIN調度表的需求。所以在
    的頭像 發表于 05-11 08:21 ?658次閱讀
    TSMaster <b class='flag-5'>自定義</b> LIN 調度表編程指導
    主站蜘蛛池模板: 亚洲国产欧美在线看片| 快穿做妓女好爽H| 福利啪啪吧| AV天堂午夜精品一区| 91精选国产| 879影视动漫h免费观看| 在线观看免费国产成人软件| 香蕉久久一区二区三区啪啪| 视频一区亚洲视频无码| 深爱激情站| 手机伊在人线香蕉2| 视频一区在线免费观看| 思思久99久女女精品| 午夜爱情动作片P| 午夜片神马影院福利| 亚洲国产成人在线| 亚洲AV精品无码喷水直播间| 亚洲m男在线中文字幕| 亚洲福利网站| 亚洲欧美一级久久精品| 一品道门免费高清视频| 樱花动漫成人隐藏入口| 2022精品福利在线小视频| 2022国产91精品久久久久久| CHINA末成年VIDEO学生| 成人免费看片又大又黄| 国产精品AV视频一二三区| 国产午夜电影在线观看不卡| 护士被老头边摸边吃奶的视频| 精品久久久久久久国产潘金莲| 久久66热在线视频精品| 老女人与小伙子露脸对白| 欧美香蕉大胸在线视频观看| 日日夜夜噜噜| 亚洲精品国产精品麻豆99| 在线亚洲精品福利网址导航| 99久久久久亚洲AV无码| 国产成人拍精品免费视频爱情岛 | china chinese中国人玩| 草柳最新地址| 国产日韩欧美高清免费视频|