最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring Security方法鑒權(quán)的實現(xiàn)

 更新時間:2023年12月18日 11:10:18   作者:龍鶴鹿  
在Spring Security中,主要有兩種鑒權(quán)方式,一個是基于web請求的鑒權(quán),一個是基于方法的鑒權(quán),本文就來介紹一下Spring Security方法鑒權(quán)的實現(xiàn),感興趣的可以了解一下

介紹

在Spring Security中,主要有兩種鑒權(quán)方式,一個是基于web請求的鑒權(quán),一個是基于方法的鑒權(quán)。無論哪種鑒權(quán),都最終會交由AuhtorizationManager執(zhí)行權(quán)限檢查。

@FunctionalInterface
public interface AuthorizationManager<T> {
    default void verify(Supplier<Authentication> authentication, T object) {
       AuthorizationDecision decision = check(authentication, object);
       if (decision != null && !decision.isGranted()) {
          throw new AccessDeniedException("Access Denied");
       }
    }

    @Nullable
    AuthorizationDecision check(Supplier<Authentication> authentication, T object);

}

從AuthorizationManager#check方法可以看出,如果要執(zhí)行權(quán)限檢查,那么必要的兩個要素是Authentication和被保護的對象。

Authenticaion已經(jīng)在登錄過程中保存到了SecurityContext中,是拿來直接用的對象

被保護的對象(即:secureObject),原則上可以是任何類型。在實際的應用中,主要是以下幾個:

  • HttpServletRequest,在對根據(jù)路徑進行模式匹配時使用
  • RequestAuthorizationContext,在對根據(jù)表達式對Web請求執(zhí)行權(quán)限檢查時使用
  • MethodInvocation,在執(zhí)行方法鑒權(quán)時使用

基于web請求的鑒權(quán),可以通過配置SecurityFilterChain來根據(jù)請求的Path、Method等檢查權(quán)限。比如:

http
    .authorizeHttpRequests(requests -> requests
        .dispatcherTypeMatchers(DispatcherType.ERROR).permitAll()
        .requestMatchers("/login/redirect").permitAll()
        .requestMatchers("/secured/foo").hasAuthority("P0")
        .anyRequest().authenticated());

對于方法鑒權(quán),通常是通過annotation來進行的。

方法鑒權(quán)實戰(zhàn)

常用的有四個注解:@PreAuthorize,@PostAuthorize,@PreFilter以及@PostFilter。他們的使用非常簡單,如下:

標準方式

在配置類上添加注解:@EnableMethodSecurity

@Configuration
@EnableMethodSecurity
public class SomeConfiguration {
    // ...
}

在Service或者Controller的方法上添加相應注解

@GetMapping("/other")
@PreAuthorize("hasAuthority('P1')") // 擁有P1權(quán)限才可以方法該方法
public String other(HttpSession session) {
    return getUsername() + "其他資源: " + session.getId();
}

注:@PreAuthorize等注解的參數(shù)中,之所以能夠使用一些內(nèi)置對象和方法(比如:hasRole、returnObject,principal),是因為使用的上下文對象中,有一個root對象(MethodSecurityExpressionOperations),所有這些注解中使用的內(nèi)置對象和方法都來自它。

擴展

有些時候,默認的方式不能滿足業(yè)務(wù)需求,比如:從Authentication#getAuthorities得到的信息不足以滿足業(yè)務(wù)需求,需要從數(shù)據(jù)庫中查詢數(shù)據(jù)。此時就需要擴展Spring Security的授權(quán)功能。
從擴展范圍從小到大可以分為如下三種擴展方式:

  • 自定義Bean,然后提供權(quán)限檢查方法
  • 自定義MethodSecurityExpressionHandler
  • 指定自己的AuthrozationManager實現(xiàn)

自定義Bean

這種方式,是完全無侵入的擴展,只需要向Spring容器注冊一個Bean,給一個名字,然后接可以在@PreAuthorize等注解中使用這個bean的方法。

定義Bean

@Component("authz")
  public class CipherAuthorization {
      public boolean hasPerm(String permission) {
          // 從數(shù)據(jù)庫中查詢當前登錄用戶的所有權(quán)限
          // 查看permission是否在返回的權(quán)限集合之中,是則返回true,否則false
          boolean foundMatch = ...
          return foundMatch;
      }
  }

在業(yè)務(wù)類中使用

@Service
public class MyService {
    
    @PreAuthorize("@authz.hasPerm('system:edit')")
    public void updateData(...) {
        //...
    }
}

自定義MethodSecurityExpressionHandler

這種方式,可以修改解析@PreAuthorize表達式的方式。通常我們可以復用DefaultMethodSecurityExpressionHandler,或者實現(xiàn)一個它的子類。無論哪種方式,都是對這個Handler進行了定制。比如:

@Bean
static MethodSecurityExpressionHandler methodSecurityExpressionHandler() {
    DefaultMethodSecurityExpressionHandler handler = new DefaultMethodSecurityExpressionHandler();
    // 定制handler,比如指定一個RoleHierarchy
    return handler;
}

指定自己的AuthorizationManager

這種方式,是徹底定制化了權(quán)限檢查的整個過程,完全使用我們自己定義的AuthorizationManager實現(xiàn)類。比如:
先定一個自定義的AuthorizationManager類:

@Component
public class MyAuthorizationManager implements AuthorizationManager<MethodInvocation> {

    @Override
    public AuthorizationDecision check(Supplier<Authentication> authentication, MethodInvocation invocation) {
        // 執(zhí)行自己的權(quán)限檢查
    }
}

然后,在Configuration中指定它:

@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
Advisor preAuthorize(MyAuthorizationManager manager) {
    return AuthorizationManagerBeforeMethodInterceptor.preAuthorize(manager);
}

原理分析

配置分析

在方法鑒權(quán)中,使用了Spring AOP(當然,也可以指定AspectJ實現(xiàn))來攔截被注解的方法。每個注解都對應一個Advisor。這一點,可以通過@EnableMethodSecurity這個注解查看。

//...
@Import(MethodSecuritySelector.class)
public @interface EnableMethodSecurity {
    //...
}

這里import了MethodSecuritySelector,它的主要內(nèi)容如下:

if (annotation.prePostEnabled()) {
    imports.add(PrePostMethodSecurityConfiguration.class.getName());
}
if (annotation.securedEnabled()) {
    imports.add(SecuredMethodSecurityConfiguration.class.getName());
}
if (annotation.jsr250Enabled()) {
    imports.add(Jsr250MethodSecurityConfiguration.class.getName());
}

對于@PreAuthorize和PostAuthorize兩個注解來說,使用到了同一個配置類:PrePostMethodSecurityConfiguration。

這里拿@PreAuthorize來說,這個類的主要內(nèi)容如下:

@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
Advisor preAuthorizeAuthorizationMethodInterceptor(...) {
    PreAuthorizeAuthorizationManager manager = new PreAuthorizeAuthorizationManager();
    manager.setExpressionHandler(
           expressionHandlerProvider.getIfAvailable(() -> defaultExpressionHandler(defaultsProvider, context)));
    AuthorizationManagerBeforeMethodInterceptor preAuthorize = AuthorizationManagerBeforeMethodInterceptor
           .preAuthorize(manager(manager, registryProvider));
    strategyProvider.ifAvailable(preAuthorize::setSecurityContextHolderStrategy);
    eventPublisherProvider.ifAvailable(preAuthorize::setAuthorizationEventPublisher);
    return preAuthorize;
}

可以看到,處理@PreAuthorize注解的Advisor是AuthorizationManagerBeforeMethodInterceptor,而AuthorizationManager是PreAuthorizeAuthorizationManager。

運行分析

有了上述的配置,再來看運行。

首先看AuthorizationManagerBeforeMethodInterceptor,在這個類里面,可以看到如下方法:

@Override
public Object invoke(MethodInvocation mi) throws Throwable {
    attemptAuthorization(mi);
    return mi.proceed();
}

它用來開啟權(quán)限檢查,而權(quán)限檢查本身其實是通過調(diào)用AuthorizationManager#check方法來進行的。
接下來,我們再看PreAuthorizeAuthorizationManager,這個類是處理@PreAuthorize注解的授權(quán)管理器。它的主要內(nèi)容如下:

@Override
public AuthorizationDecision check(Supplier<Authentication> authentication, MethodInvocation mi) {
    ExpressionAttribute attribute = this.registry.getAttribute(mi);
    if (attribute == ExpressionAttribute.NULL_ATTRIBUTE) {
       return null;
    }
    EvaluationContext ctx = this.registry.getExpressionHandler().createEvaluationContext(authentication, mi);
    boolean granted = ExpressionUtils.evaluateAsBoolean(attribute.getExpression(), ctx);
    return new ExpressionAuthorizationDecision(granted, attribute.getExpression());
}

可以看到,它首先從registry中找到MethodSecurityExpressionHandler,然后通過調(diào)用它的createEvaluationContext方法獲取EvaluationContext,然后對@PreAuthorize的參數(shù)(SpEL表達式)進行計算,得到一個布爾值,決定是否通過權(quán)限檢查。

到此這篇關(guān)于Spring Security方法鑒權(quán)的實現(xiàn)的文章就介紹到這了,更多相關(guān)SpringSecurity方法鑒權(quán)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Feign實現(xiàn)多文件上傳,Open?Feign多文件上傳問題及解決

    Feign實現(xiàn)多文件上傳,Open?Feign多文件上傳問題及解決

    這篇文章主要介紹了Feign實現(xiàn)多文件上傳,Open?Feign多文件上傳問題及解決,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • 詳解maven配置多倉庫的方法示例

    詳解maven配置多倉庫的方法示例

    這篇文章主要介紹了詳解maven配置多倉庫的方法示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-08-08
  • Intellij IDEA連接Navicat數(shù)據(jù)庫的方法

    Intellij IDEA連接Navicat數(shù)據(jù)庫的方法

    這篇文章主要介紹了Intellij IDEA連接Navicat數(shù)據(jù)庫的方法,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借價值,需要的朋友可以參考下
    2021-03-03
  • 簡單介紹區(qū)分applet和application的方法

    簡單介紹區(qū)分applet和application的方法

    applet和application都是Java語言編寫出來的應用程序,本文簡單介紹了二者的不同之處,需要的朋友可以參考下
    2017-09-09
  • springboot對接minio的webhook完整步驟記錄

    springboot對接minio的webhook完整步驟記錄

    Minio是一款開源的對象存儲服務(wù),它致力于為開發(fā)者提供簡單、高性能、高可用的云存儲解決方案,下面這篇文章主要給大家介紹了關(guān)于springboot對接minio的webhook的相關(guān)資料,需要的朋友可以參考下
    2024-07-07
  • java實現(xiàn)打印正三角的方法

    java實現(xiàn)打印正三角的方法

    這篇文章主要為大家詳細介紹了java實現(xiàn)打印正三角的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • SpringBoot實現(xiàn)TCP連接并進行數(shù)據(jù)互傳的方法

    SpringBoot實現(xiàn)TCP連接并進行數(shù)據(jù)互傳的方法

    本文詳細介紹了微服務(wù)架構(gòu)中的翻譯組件使用場景,以及多種開源翻譯組件的解決方案,文中分析了國內(nèi)外多個翻譯服務(wù)如百度翻譯、谷歌翻譯等,以及如何在微服務(wù)項目中集成這些翻譯組件,感興趣的朋友跟隨小編一起看看吧
    2024-11-11
  • Springboot+rabbitmq實現(xiàn)延時隊列的兩種方式

    Springboot+rabbitmq實現(xiàn)延時隊列的兩種方式

    這篇文章主要介紹了Springboot+rabbitmq實現(xiàn)延時隊列的兩種方式,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-05-05
  • SpringBoot中的@RequestMapping注解的用法示例

    SpringBoot中的@RequestMapping注解的用法示例

    @RequestMapping注解是SpringBoot中最常用的注解之一,它可以幫助開發(fā)者定義和處理HTTP請求,本篇文章我們將詳細為大家介紹如何使用SpringBoot中的@RequestMapping注解,感興趣的同學跟著小編一起來學習吧
    2023-06-06
  • 使用Java實現(xiàn)查看線程的運行狀態(tài)(附源碼)

    使用Java實現(xiàn)查看線程的運行狀態(tài)(附源碼)

    在現(xiàn)代 Java 應用中,線程的運行狀態(tài)對于排查問題和優(yōu)化性能具有至關(guān)重要的作用,本文將使用Java編寫一個查看線程運行狀態(tài)的工具,有需要的可以了解下
    2025-03-03

最新評論

博湖县| 桂平市| 舒兰市| 四会市| 常宁市| 潮安县| 甘肃省| 华蓥市| 元氏县| 隆化县| 民乐县| 金秀| 龙江县| 通州区| 红原县| 德化县| 昌黎县| 建瓯市| 特克斯县| 江达县| 卓尼县| 小金县| 化德县| 衡山县| 礼泉县| 张家口市| 页游| 衡阳市| 工布江达县| 高安市| 互助| 古田县| 云安县| 九龙城区| 方正县| 石台县| 万年县| 崇阳县| 靖西县| 江津市| 荔浦县|