HttpSecurity是什么

這篇文章主要介紹“HttpSecurity是什么”,在日常操作中,相信很多人在HttpSecurity是什么問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”HttpSecurity是什么”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!

公司主營(yíng)業(yè)務(wù):成都網(wǎng)站設(shè)計(jì)、網(wǎng)站建設(shè)、外貿(mào)網(wǎng)站建設(shè)、移動(dòng)網(wǎng)站開(kāi)發(fā)等業(yè)務(wù)。幫助企業(yè)客戶真正實(shí)現(xiàn)互聯(lián)網(wǎng)宣傳,提高企業(yè)的競(jìng)爭(zhēng)能力。創(chuàng)新互聯(lián)公司是一支青春激揚(yáng)、勤奮敬業(yè)、活力青春激揚(yáng)、勤奮敬業(yè)、活力澎湃、和諧高效的團(tuán)隊(duì)。公司秉承以“開(kāi)放、自由、嚴(yán)謹(jǐn)、自律”為核心的企業(yè)文化,感謝他們對(duì)我們的高要求,感謝他們從不同領(lǐng)域給我們帶來(lái)的挑戰(zhàn),讓我們激情的團(tuán)隊(duì)有機(jī)會(huì)用頭腦與智慧不斷的給客戶帶來(lái)驚喜。創(chuàng)新互聯(lián)公司推出容城免費(fèi)做網(wǎng)站回饋大家。

1.抽絲剝繭

首先我們來(lái)看下 HttpSecurity 的繼承關(guān)系圖:

HttpSecurity是什么  

可以看到,HttpSecurity 繼承自 AbstractConfiguredSecurityBuilder,同時(shí)實(shí)現(xiàn)了 SecurityBuilder 和 HttpSecurityBuilder 兩個(gè)接口。

我們來(lái)看下 HttpSecurity 的定義:

public final class HttpSecurity extends
  AbstractConfiguredSecurityBuilder<DefaultSecurityFilterChain, HttpSecurity>
  implements SecurityBuilder<DefaultSecurityFilterChain>,
  HttpSecurityBuilder<HttpSecurity> {
        //...
}
 

這里每一個(gè)類都帶有泛型,看得人有點(diǎn)眼花繚亂。

我把這個(gè)泛型類拿出來(lái)和大家講一下,小伙伴們就明白了。

泛型主要是兩個(gè),DefaultSecurityFilterChain 和 HttpSecurity,HttpSecurity 就不用說(shuō)了,這是我們今天的主角,那么 DefaultSecurityFilterChain 是干嘛的?

這我們就得從 SecurityFilterChain 說(shuō)起了。

 

1.1 SecurityFilterChain

先來(lái)看定義:

public interface SecurityFilterChain {
 boolean matches(HttpServletRequest request);
 List<Filter> getFilters();
}
 

SecurityFilterChain 其實(shí)就是我們平時(shí)所說(shuō)的 Spring Security 中的過(guò)濾器鏈,它里邊定義了兩個(gè)方法,一個(gè)是 matches 方法用來(lái)匹配請(qǐng)求,另外一個(gè) getFilters 方法返回一個(gè) List 集合,集合中放著 Filter 對(duì)象,當(dāng)一個(gè)請(qǐng)求到來(lái)時(shí),用 matches 方法去比較請(qǐng)求是否和當(dāng)前鏈吻合,如果吻合,就返回 getFilters 方法中的過(guò)濾器,那么當(dāng)前請(qǐng)求會(huì)逐個(gè)經(jīng)過(guò) List 集合中的過(guò)濾器。這

SecurityFilterChain 接口只有一個(gè)實(shí)現(xiàn)類,那就是 DefaultSecurityFilterChain:

public final class DefaultSecurityFilterChain implements SecurityFilterChain {
 private static final Log logger = LogFactory.getLog(DefaultSecurityFilterChain.class);
 private final RequestMatcher requestMatcher;
 private final List<Filter> filters;

 public DefaultSecurityFilterChain(RequestMatcher requestMatcher, Filter... filters) {
  this(requestMatcher, Arrays.asList(filters));
 }

 public DefaultSecurityFilterChain(RequestMatcher requestMatcher, List<Filter> filters) {
  logger.info("Creating filter chain: " + requestMatcher + ", " + filters);
  this.requestMatcher = requestMatcher;
  this.filters = new ArrayList<>(filters);
 }

 public RequestMatcher getRequestMatcher() {
  return requestMatcher;
 }

 public List<Filter> getFilters() {
  return filters;
 }

 public boolean matches(HttpServletRequest request) {
  return requestMatcher.matches(request);
 }

 @Override
 public String toString() {
  return "[ " + requestMatcher + ", " + filters + "]";
 }
}
 

DefaultSecurityFilterChain 只是對(duì) SecurityFilterChain 中的方法進(jìn)行了實(shí)現(xiàn),并沒(méi)有特別值得說(shuō)的地方,松哥也就不啰嗦了。

那么從上面的介紹中,大家可以看到,DefaultSecurityFilterChain 其實(shí)就相當(dāng)于是 Spring Security 中的過(guò)濾器鏈,一個(gè) DefaultSecurityFilterChain 代表一個(gè)過(guò)濾器鏈,如果系統(tǒng)中存在多個(gè)過(guò)濾器鏈,則會(huì)存在多個(gè) DefaultSecurityFilterChain 對(duì)象。

接下來(lái)我們把 HttpSecurity 的這幾個(gè)父類捋一捋。

 

1.2 SecurityBuilder

public interface SecurityBuilder<O> {
 O build() throws Exception;
}
 

SecurityBuilder 就是用來(lái)構(gòu)建過(guò)濾器鏈的,在 HttpSecurity 實(shí)現(xiàn) SecurityBuilder 時(shí),傳入的泛型就是 DefaultSecurityFilterChain,所以 SecurityBuilder#build 方法的功能很明確,就是用來(lái)構(gòu)建一個(gè)過(guò)濾器鏈出來(lái)。

 

1.3 HttpSecurityBuilder

HttpSecurityBuilder 看名字就是用來(lái)構(gòu)建 HttpSecurity 的。不過(guò)它也只是一個(gè)接口,具體的實(shí)現(xiàn)在 HttpSecurity 中,接口定義如下:

public interface HttpSecurityBuilder<H extends HttpSecurityBuilder<H>> extends
  SecurityBuilder<DefaultSecurityFilterChain> {
 <C extends SecurityConfigurer<DefaultSecurityFilterChain, H>> C getConfigurer(
   Class<C> clazz);
 <C extends SecurityConfigurer<DefaultSecurityFilterChain, H>> C removeConfigurer(
   Class<C> clazz);
 <C> void setSharedObject(Class<C> sharedType, C object);
 <C> C getSharedObject(Class<C> sharedType);
 H authenticationProvider(AuthenticationProvider authenticationProvider);
 H userDetailsService(UserDetailsService userDetailsService) throws Exception;
 H addFilterAfter(Filter filter, Class<? extends Filter> afterFilter);
 H addFilterBefore(Filter filter, Class<? extends Filter> beforeFilter);
 H addFilter(Filter filter);
}
 

這里的方法比較簡(jiǎn)單:

  1. getConfigurer 獲取一個(gè)配置對(duì)象。Spring Security 過(guò)濾器鏈中的所有過(guò)濾器對(duì)象都是由 xxxConfigure 來(lái)進(jìn)行配置的,這里就是獲取這個(gè) xxxConfigure 對(duì)象。
  2. removeConfigurer 移除一個(gè)配置對(duì)象。
  3. setSharedObject/getSharedObject 配置/獲取由多個(gè) SecurityConfigurer 共享的對(duì)象。
  4. authenticationProvider 方法表示配置驗(yàn)證器。
  5. userDetailsService 配置數(shù)據(jù)源接口。
  6. addFilterAfter 在某一個(gè)過(guò)濾器之前添加過(guò)濾器。
  7. addFilterBefore 在某一個(gè)過(guò)濾器之后添加過(guò)濾器。
  8. addFilter 添加一個(gè)過(guò)濾器,該過(guò)濾器必須是現(xiàn)有過(guò)濾器鏈中某一個(gè)過(guò)濾器或者其擴(kuò)展。

這便是 HttpSecurityBuilder 中的功能,這些接口在 HttpSecurity 中都將得到實(shí)現(xiàn)。

 

1.4 AbstractSecurityBuilder

AbstractSecurityBuilder 類實(shí)現(xiàn)了 SecurityBuilder 接口,該類中主要做了一件事,就是確保整個(gè)構(gòu)建只被構(gòu)建一次。

public abstract class AbstractSecurityBuilder<O> implements SecurityBuilder<O> {
 private AtomicBoolean building = new AtomicBoolean();
 private O object;
 public final O build() throws Exception {
  if (this.building.compareAndSet(false, true)) {
   this.object = doBuild();
   return this.object;
  }
  throw new AlreadyBuiltException("This object has already been built");
 }
 public final O getObject() {
  if (!this.building.get()) {
   throw new IllegalStateException("This object has not been built");
  }
  return this.object;
 }
 protected abstract O doBuild() throws Exception;
}
 

可以看到,這里重新定義了 build 方法,并設(shè)置 build 方法為 final 類型,無(wú)法被重寫(xiě),在 build 方法中,通過(guò) AtomicBoolean 實(shí)現(xiàn)該方法只被調(diào)用一次。具體的構(gòu)建邏輯則定義了新的抽象方法 doBuild,將來(lái)在實(shí)現(xiàn)類中通過(guò) doBuild 方法定義構(gòu)建邏輯。

 

1.5 AbstractConfiguredSecurityBuilder

AbstractSecurityBuilder 方法的實(shí)現(xiàn)類就是 AbstractConfiguredSecurityBuilder。

AbstractConfiguredSecurityBuilder 中所做的事情就比較多了,我們分別來(lái)看。

首先 AbstractConfiguredSecurityBuilder 中定義了一個(gè)枚舉類,將整個(gè)構(gòu)建過(guò)程分為 5 種狀態(tài),也可以理解為構(gòu)建過(guò)程生命周期的五個(gè)階段,如下:

private enum BuildState {
 UNBUILT(0),
 INITIALIZING(1),
 CONFIGURING(2),
 BUILDING(3),
 BUILT(4);
 private final int order;
 BuildState(int order) {
  this.order = order;
 }
 public boolean isInitializing() {
  return INITIALIZING.order == order;
 }
 public boolean isConfigured() {
  return order >= CONFIGURING.order;
 }
}
 

五種狀態(tài)分別是 UNBUILT、INITIALIZING、CONFIGURING、BUILDING 以及 BUILT。另外還提供了兩個(gè)判斷方法,isInitializing 判斷是否正在初始化,isConfigured 表示是否已經(jīng)配置完畢。

AbstractConfiguredSecurityBuilder 中的方法比較多,松哥在這里列出來(lái)兩個(gè)關(guān)鍵的方法和大家分析:

private <C extends SecurityConfigurer<O, B>> void add(C configurer) {
 Assert.notNull(configurer, "configurer cannot be null");
 Class<? extends SecurityConfigurer<O, B>> clazz = (Class<? extends SecurityConfigurer<O, B>>) configurer
   .getClass();
 synchronized (configurers) {
  if (buildState.isConfigured()) {
   throw new IllegalStateException("Cannot apply " + configurer
     + " to already built object");
  }
  List<SecurityConfigurer<O, B>> configs = allowConfigurersOfSameType ? this.configurers
    .get(clazz) : null;
  if (configs == null) {
   configs = new ArrayList<>(1);
  }
  configs.add(configurer);
  this.configurers.put(clazz, configs);
  if (buildState.isInitializing()) {
   this.configurersAddedInInitializing.add(configurer);
  }
 }
}
private Collection<SecurityConfigurer<O, B>> getConfigurers() {
 List<SecurityConfigurer<O, B>> result = new ArrayList<>();
 for (List<SecurityConfigurer<O, B>> configs : this.configurers.values()) {
  result.addAll(configs);
 }
 return result;
}
 

第一個(gè)就是這個(gè) add 方法,這相當(dāng)于是在收集所有的配置類。將所有的 xxxConfigure 收集起來(lái)存儲(chǔ)到 configurers 中,將來(lái)再統(tǒng)一初始化并配置,configurers 本身是一個(gè) LinkedHashMap ,key 是配置類的 class,value 是一個(gè)集合,集合里邊放著 xxxConfigure 配置類。當(dāng)需要對(duì)這些配置類進(jìn)行集中配置的時(shí)候,會(huì)通過(guò) getConfigurers 方法獲取配置類,這個(gè)獲取過(guò)程就是把 LinkedHashMap 中的 value 拿出來(lái),放到一個(gè)集合中返回。

另一個(gè)方法就是 doBuild 方法。

@Override
protected final O doBuild() throws Exception {
 synchronized (configurers) {
  buildState = BuildState.INITIALIZING;
  beforeInit();
  init();
  buildState = BuildState.CONFIGURING;
  beforeConfigure();
  configure();
  buildState = BuildState.BUILDING;
  O result = performBuild();
  buildState = BuildState.BUILT;
  return result;
 }
}
private void init() throws Exception {
 Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();
 for (SecurityConfigurer<O, B> configurer : configurers) {
  configurer.init((B) this);
 }
 for (SecurityConfigurer<O, B> configurer : configurersAddedInInitializing) {
  configurer.init((B) this);
 }
}
private void configure() throws Exception {
 Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();
 for (SecurityConfigurer<O, B> configurer : configurers) {
  configurer.configure((B) this);
 }
}
 

在 AbstractSecurityBuilder 類中,過(guò)濾器的構(gòu)建被轉(zhuǎn)移到 doBuild 方法上面了,不過(guò)在 AbstractSecurityBuilder 中只是定義了抽象的 doBuild 方法,具體的實(shí)現(xiàn)在 AbstractConfiguredSecurityBuilder。

doBuild 方法就是一邊更新?tīng)顟B(tài),進(jìn)行進(jìn)行初始化。

beforeInit 是一個(gè)預(yù)留方法,沒(méi)有任何實(shí)現(xiàn)。

init 方法就是找到所有的 xxxConfigure,挨個(gè)調(diào)用其 init 方法進(jìn)行初始化。

beforeConfigure 是一個(gè)預(yù)留方法,沒(méi)有任何實(shí)現(xiàn)。

configure 方法就是找到所有的 xxxConfigure,挨個(gè)調(diào)用其 configure 方法進(jìn)行配置。

最后則是 performBuild 方法,是真正的過(guò)濾器鏈構(gòu)建方法,但是在 AbstractConfiguredSecurityBuilder 中 performBuild 方法只是一個(gè)抽象方法,具體的實(shí)現(xiàn)在 HttpSecurity 中。

這便是 HttpSecurity 所有父類、父接口的功能。

看完了父輩,接下來(lái)回到我們今天文章的主題,HttpSecurity。

 

2. HttpSecurity

HttpSecurity 做的事情,就是進(jìn)行各種各樣的 xxxConfigurer 配置。

隨便舉幾例:

public CorsConfigurer<HttpSecurity> cors() throws Exception {
 return getOrApply(new CorsConfigurer<>());
}
public CsrfConfigurer<HttpSecurity> csrf() throws Exception {
 ApplicationContext context = getContext();
 return getOrApply(new CsrfConfigurer<>(context));
}
public ExceptionHandlingConfigurer<HttpSecurity> exceptionHandling() throws Exception {
 return getOrApply(new ExceptionHandlingConfigurer<>());
}
 

HttpSecurity 中有大量類似的方法,過(guò)濾器鏈中的過(guò)濾器就是這樣一個(gè)一個(gè)配置的。我就不一一介紹了。

每個(gè)配置方法的結(jié)尾都會(huì)來(lái)一句 getOrApply,這個(gè)是干嘛的?

private <C extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity>> C getOrApply(
  C configurer) throws Exception {
 C existingConfig = (C) getConfigurer(configurer.getClass());
 if (existingConfig != null) {
  return existingConfig;
 }
 return apply(configurer);
}
 

getConfigurer 方法是在它的父類 AbstractConfiguredSecurityBuilder 中定義的,目的就是去查看當(dāng)前這個(gè) xxxConfigurer 是否已經(jīng)配置過(guò)了。

如果當(dāng)前 xxxConfigurer 已經(jīng)配置過(guò)了,則直接返回,否則調(diào)用 apply 方法,這個(gè) apply 方法最終會(huì)調(diào)用到 AbstractConfiguredSecurityBuilder#add 方法,將當(dāng)前配置 configurer 收集起來(lái)。

HttpSecurity 中還有一個(gè) addFilter 方法:

public HttpSecurity addFilter(Filter filter) {
 Class<? extends Filter> filterClass = filter.getClass();
 if (!comparator.isRegistered(filterClass)) {
  throw new IllegalArgumentException(
    "The Filter class "
      + filterClass.getName()
      + " does not have a registered order and cannot be added without a specified order. Consider using addFilterBefore or addFilterAfter instead.");
 }
 this.filters.add(filter);
 return this;
}
 

這個(gè) addFilter 方法的作用,主要是在各個(gè) xxxConfigurer 進(jìn)行配置的時(shí)候,會(huì)調(diào)用到這個(gè)方法,(xxxConfigurer 就是用來(lái)配置過(guò)濾器的),把 Filter 都添加到 fitlers 變量中。

最終在 HttpSecurity 的 performBuild 方法中,構(gòu)建出來(lái)一個(gè)過(guò)濾器鏈:

@Override
protected DefaultSecurityFilterChain performBuild() {
 filters.sort(comparator);
 return new DefaultSecurityFilterChain(requestMatcher, filters);
}

先給過(guò)濾器排序,然后構(gòu)造 DefaultSecurityFilterChain 對(duì)象。

到此,關(guān)于“HttpSecurity是什么”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!

新聞名稱:HttpSecurity是什么
文章網(wǎng)址:http://muchs.cn/article38/gphspp.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供移動(dòng)網(wǎng)站建設(shè)、靜態(tài)網(wǎng)站、營(yíng)銷型網(wǎng)站建設(shè)、建站公司、軟件開(kāi)發(fā)、網(wǎng)站設(shè)計(jì)公司

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

微信小程序開(kāi)發(fā)