欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

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

介紹

在Spring Security中,主要有兩種鑒權(quán)方式,一個(gè)是基于web請(qǐng)求的鑒權(quán),一個(gè)是基于方法的鑒權(quán)。無論哪種鑒權(quán),都最終會(huì)交由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)限檢查,那么必要的兩個(gè)要素是Authentication和被保護(hù)的對(duì)象。

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

被保護(hù)的對(duì)象(即:secureObject),原則上可以是任何類型。在實(shí)際的應(yīng)用中,主要是以下幾個(gè):

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

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

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

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

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

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

標(biāo)準(zhǔn)方式

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

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

在Service或者Controller的方法上添加相應(yīng)注解

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

注:@PreAuthorize等注解的參數(shù)中,之所以能夠使用一些內(nèi)置對(duì)象和方法(比如:hasRole、returnObject,principal),是因?yàn)槭褂玫纳舷挛膶?duì)象中,有一個(gè)root對(duì)象(MethodSecurityExpressionOperations),所有這些注解中使用的內(nèi)置對(duì)象和方法都來自它。

擴(kuò)展

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

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

自定義Bean

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

定義Bean

@Component("authz")
  public class CipherAuthorization {
      public boolean hasPerm(String permission) {
          // 從數(shù)據(jù)庫中查詢當(dāng)前登錄用戶的所有權(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表達(dá)式的方式。通常我們可以復(fù)用DefaultMethodSecurityExpressionHandler,或者實(shí)現(xiàn)一個(gè)它的子類。無論哪種方式,都是對(duì)這個(gè)Handler進(jìn)行了定制。比如:

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

指定自己的AuthorizationManager

這種方式,是徹底定制化了權(quán)限檢查的整個(gè)過程,完全使用我們自己定義的AuthorizationManager實(shí)現(xiàn)類。比如:
先定一個(gè)自定義的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(當(dāng)然,也可以指定AspectJ實(shí)現(xiàn))來攔截被注解的方法。每個(gè)注解都對(duì)應(yīng)一個(gè)Advisor。這一點(diǎn),可以通過@EnableMethodSecurity這個(gè)注解查看。

//...
@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());
}

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

這里拿@PreAuthorize來說,這個(gè)類的主要內(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。

運(yùn)行分析

有了上述的配置,再來看運(yùn)行。

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

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

它用來開啟權(quán)限檢查,而權(quán)限檢查本身其實(shí)是通過調(diào)用AuthorizationManager#check方法來進(jìn)行的。
接下來,我們?cè)倏碢reAuthorizeAuthorizationManager,這個(gè)類是處理@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,然后對(duì)@PreAuthorize的參數(shù)(SpEL表達(dá)式)進(jìn)行計(jì)算,得到一個(gè)布爾值,決定是否通過權(quán)限檢查。

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

相關(guān)文章

  • SpringBoot應(yīng)用整合ELK實(shí)現(xiàn)日志收集的示例代碼

    SpringBoot應(yīng)用整合ELK實(shí)現(xiàn)日志收集的示例代碼

    這篇文章主要介紹了SpringBoot應(yīng)用整合ELK實(shí)現(xiàn)日志收集的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • java、spring、springboot中整合Redis的詳細(xì)講解

    java、spring、springboot中整合Redis的詳細(xì)講解

    這篇文章主要介紹了java、spring、springboot中整合Redis的詳細(xì)講解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • Java處理Webp圖片格式轉(zhuǎn)換的示例代碼

    Java處理Webp圖片格式轉(zhuǎn)換的示例代碼

    這篇文章主要介紹了Java處理Webp圖片格式轉(zhuǎn)換的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-09-09
  • Spring boot通過切面,實(shí)現(xiàn)超靈活的注解式數(shù)據(jù)校驗(yàn)過程

    Spring boot通過切面,實(shí)現(xiàn)超靈活的注解式數(shù)據(jù)校驗(yàn)過程

    這篇文章主要介紹了Spring boot通過切面,實(shí)現(xiàn)超靈活的注解式數(shù)據(jù)校驗(yàn)過程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • Swagger3.0 整合spring boot2.7x避免swagger2.0與boot2.7沖突問題

    Swagger3.0 整合spring boot2.7x避免swagger2.0與boot2.7沖突

    這篇文章主要介紹了Swagger3.0 整合spring boot2.7x避免swagger2.0與boot2.7沖突問題,通過注釋掉2.0引入的倆包,直接引入3.0,文中結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧
    2023-10-10
  • 在Spring?Boot中啟用HTTPS的方法

    在Spring?Boot中啟用HTTPS的方法

    本文介紹了在Spring Boot項(xiàng)目中啟用HTTPS的步驟,從生成SSL證書開始,到配置Spring Boot。HTTPS是保護(hù)Web應(yīng)用程序安全的基石之一,而Spring Boot則提供了相對(duì)簡易的途徑來配置它,感興趣的朋友跟隨小編一起看看吧
    2024-02-02
  • SpringBoot模擬員工數(shù)據(jù)庫并實(shí)現(xiàn)增刪改查操作

    SpringBoot模擬員工數(shù)據(jù)庫并實(shí)現(xiàn)增刪改查操作

    這篇文章主要給大家介紹了關(guān)于SpringBoot模擬員工數(shù)據(jù)庫并實(shí)現(xiàn)增刪改查操作的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2021-09-09
  • Java中的BigDecimal精度運(yùn)算詳解

    Java中的BigDecimal精度運(yùn)算詳解

    這篇文章主要介紹了Java中的BigDecimal精度運(yùn)算詳解,Java在java.math包中提供的API類BigDecimal,用來對(duì)超過16位有效位的數(shù)進(jìn)行精確的運(yùn)算,雙精度浮點(diǎn)型變量double可以處理16位有效數(shù),但在實(shí)際應(yīng)用中,可能需要對(duì)更大或者更小的數(shù)進(jìn)行運(yùn)算和處理,需要的朋友可以參考下
    2023-10-10
  • SpringMVC統(tǒng)一異常處理實(shí)例代碼

    SpringMVC統(tǒng)一異常處理實(shí)例代碼

    這篇文章主要介紹了SpringMVC統(tǒng)一異常處理實(shí)例代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-11-11
  • 詳解JVM棧溢出和堆溢出

    詳解JVM棧溢出和堆溢出

    今天帶大家學(xué)習(xí)的是Java的相關(guān)知識(shí),文章圍繞著JVM棧溢出和堆溢出展開,文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下
    2021-06-06

最新評(píng)論