歡迎光臨
每天分享高質量文章

Spring Security(三)–核心配置解讀

上一篇文章《Spring Security(二)–Guides》,通過Spring Security的配置項瞭解了Spring Security是如何保護我們的應用的,本篇文章對上一次的配置做一個分析。

作者:老徐

原文地址:https://www.cnkirito.moe/2017/09/20/spring-security-3/

友情提示:歡迎關註公眾號【芋道原始碼】。?關註後,拉你進【原始碼圈】微信群和【老徐】搞基嗨皮。

友情提示:歡迎關註公眾號【芋道原始碼】。?關註後,拉你進【原始碼圈】微信群和【老徐】搞基嗨皮。

友情提示:歡迎關註公眾號【芋道原始碼】。?關註後,拉你進【原始碼圈】微信群和【老徐】搞基嗨皮。


目錄

核心配置解讀

  • 3.1 功能介紹

  • 3.2 EnableWebSecurity

    • WebSecurityConfiguration

    • AuthenticationConfiguration

  • 3.3 WebSecurityConfigurerAdapter

    • HttpSecurity常用配置

    • WebSecurityBuilder

    • AuthenticationManagerBuilder

3 核心配置解讀

3.1 功能介紹

這是Spring Security入門指南中的配置項:

  1. @Configuration

  2. @EnableWebSecurity

  3. public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

  4.  @Override

  5.  protected void configure(HttpSecurity http) throws Exception {

  6.      http

  7.          .authorizeRequests()

  8.              .antMatchers("/", "/home").permitAll()

  9.              .anyRequest().authenticated()

  10.              .and()

  11.          .formLogin()

  12.              .loginPage("/login")

  13.              .permitAll()

  14.              .and()

  15.          .logout()

  16.              .permitAll();

  17.  }

  18.  @Autowired

  19.  public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {

  20.      auth

  21.          .inMemoryAuthentication()

  22.              .withUser("admin").password("admin").roles("USER");

  23.  }

  24. }

當配置了上述的javaconfig之後,我們的應用便具備瞭如下的功能:

  • 除了“/”,"/home"(首頁),"/login"(登錄),"/logout"(註銷),之外,其他路徑都需要認證。

  • 指定“/login”該路徑為登錄頁面,當未認證的用戶嘗試訪問任何受保護的資源時,都會跳轉到“/login”。

  • 預設指定“/logout”為註銷頁面

  • 配置一個記憶體中的用戶認證器,使用admin/admin作為用戶名和密碼,具有USER角色

  • 防止CSRF攻擊

  • Session Fixation protection(可以參考我之前講解Spring Session的文章,防止別人篡改sessionId)

  • Security Header(添加一系列和Header相關的控制)

    • HTTP Strict Transport Security for secure requests

    • 集成X-Content-Type-Options

    • 快取控制

    • 集成X-XSS-Protection

    • X-Frame-Options integration to help prevent Clickjacking(iframe被預設禁止使用)

  • 為Servlet API集成瞭如下的幾個方法

    • HttpServletRequest#getRemoteUser()

    • HttpServletRequest.html#getUserPrincipal()

    • HttpServletRequest.html#isUserInRole(java.lang.String)

    • HttpServletRequest.html#login(java.lang.String, java.lang.String)

    • HttpServletRequest.html#logout()

3.2 @EnableWebSecurity

我們自己定義的配置類WebSecurityConfig加上了@EnableWebSecurity註解,同時繼承了WebSecurityConfigurerAdapter。你可能會在想誰的作用大一點,毫無疑問@EnableWebSecurity起到決定性的配置作用,它其實是個組合註解。

  1. @Import({ WebSecurityConfiguration.class, // <2>

  2.      SpringWebMvcImportSelector.class }) // <1>

  3. @EnableGlobalAuthentication // <3>

  4. @Configuration

  5. public @interface EnableWebSecurity {

  6.   boolean debug() default false;

  7. }

@Import是springboot提供的用於引入外部的配置的註解,可以理解為:@EnableWebSecurity註解激活了@Import註解中包含的配置類。

<1> SpringWebMvcImportSelector的作用是判斷當前的環境是否包含springmvc,因為spring security可以在非spring環境下使用,為了避免DispatcherServlet的重覆配置,所以使用了這個註解來區分。

<2> WebSecurityConfiguration顧名思義,是用來配置web安全的,下麵的小節會詳細介紹。

<3> @EnableGlobalAuthentication註解的原始碼如下:

  1. @Import(AuthenticationConfiguration.class)

  2. @Configuration

  3. public @interface EnableGlobalAuthentication {

  4. }

註意點同樣在@Import之中,它實際上激活了AuthenticationConfiguration這樣的一個配置類,用來配置認證相關的核心類。

也就是說:@EnableWebSecurity完成的工作便是加載了WebSecurityConfiguration,AuthenticationConfiguration這兩個核心配置類,也就此將spring security的職責劃分為了配置安全信息,配置認證信息兩部分。

WebSecurityConfiguration

在這個配置類中,有一個非常重要的Bean被註冊了。

  1. @Configuration

  2. public class WebSecurityConfiguration {

  3.    //DEFAULT_FILTER_NAME = "springSecurityFilterChain"

  4.    @Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)

  5.    public Filter springSecurityFilterChain() throws Exception {

  6.        ...

  7.    }

  8. }  

在未使用springboot之前,大多數人都應該對“springSecurityFilterChain”這個名詞不會陌生,他是spring security的核心過濾器,是整個認證的入口。在曾經的XML配置中,想要啟用spring security,需要在web.xml中進行如下配置:

  1.    

  2.    

  3.        springSecurityFilterChain

  •        org.springframework.web.filter.DelegatingFilterProxy

  •    

  •    

  •        springSecurityFilterChain

  •        /*

  •    

  • 而在springboot集成之後,這樣的XML被java配置取代。WebSecurityConfiguration中完成了宣告springSecurityFilterChain的作用,並且最終交給DelegatingFilterProxy這個代理類,負責攔截請求(註意DelegatingFilterProxy這個類不是spring security包中的,而是存在於web包中,spring使用了代理樣式來實現安全過濾的解耦)。

    AuthenticationConfiguration

    1. @Configuration

    2. @Import(ObjectPostProcessorConfiguration.class)

    3. public class AuthenticationConfiguration {

    4.      @Bean

    5.    public AuthenticationManagerBuilder authenticationManagerBuilder(

    6.            ObjectPostProcessor<Object> objectPostProcessor) {

    7.        return new AuthenticationManagerBuilder(objectPostProcessor);

    8.    }

    9.      public AuthenticationManager getAuthenticationManager() throws Exception {

    10.        ...

    11.    }

    12. }

    AuthenticationConfiguration的主要任務,便是負責生成全域性的身份認證管理者AuthenticationManager。還記得在《Spring Security(一)--Architecture Overview》中,介紹了Spring Security的認證體系,AuthenticationManager便是最核心的身份認證管理器。

    3.3 WebSecurityConfigurerAdapter

    配接器樣式在spring中被廣泛的使用,在配置中使用Adapter的好處便是,我們可以選擇性的配置想要修改的那一部分配置,而不用改寫其他不相關的配置。WebSecurityConfigurerAdapter中我們可以選擇自己想要修改的內容,來進行重寫,而其提供了三個configure多載方法,是我們主要關心的:

    由引數就可以知道,分別是對AuthenticationManagerBuilder,WebSecurity,HttpSecurity進行個性化的配置。

    HttpSecurity常用配置

    1. @Configuration

    2. @EnableWebSecurity

    3. public class CustomWebSecurityConfig extends WebSecurityConfigurerAdapter {

    4.    @Override

    5.    protected void configure(HttpSecurity http) throws Exception {

    6.        http

    7.            .authorizeRequests()

    8.                .antMatchers("/resources/**", "/signup", "/about").permitAll()

    9.                .antMatchers("/admin/**").hasRole("ADMIN")

    10.                .antMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')")

    11.                .anyRequest().authenticated()

    12.                .and()

    13.            .formLogin()

    14.                .usernameParameter("username")

    15.                .passwordParameter("password")

    16.                .failureForwardUrl("/login?error")

    17.                .loginPage("/login")

    18.                .permitAll()

    19.                .and()

    20.            .logout()

    21.                .logoutUrl("/logout")

    22.                .logoutSuccessUrl("/index")

    23.                .permitAll()

    24.                .and()

    25.            .httpBasic()

    26.                .disable();

    27.    }

    28. }

    上述是一個使用Java Configuration配置HttpSecurity的典型配置,其中http作為根開始配置,每一個and()對應了一個模塊的配置(等同於xml配置中的結束標簽),並且and()傳回了HttpSecurity本身,於是可以連續進行配置。他們配置的含義也非常容易通過變數本身來推測,

    • authorizeRequests()配置路徑攔截,表明路徑訪問所對應的權限,角色,認證信息。

    • formLogin()對應表單認證相關的配置

    • logout()對應了註銷相關的配置

    • httpBasic()可以配置basic登錄

    • etc

    他們分別代表了http請求相關的安全配置,這些配置項無一例外的傳回了Configurer類,而所有的http相關配置可以通過查看HttpSecurity的主要方法得知:

    需要對http協議有一定的瞭解才能完全掌握所有的配置,不過,springboot和spring security的自動配置已經足夠使用了。其中每一項Configurer(e.g.FormLoginConfigurer,CsrfConfigurer)都是HttpConfigurer的細化配置項。

    WebSecurityBuilder

    1. @Configuration

    2. @EnableWebSecurity

    3. public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    4.    @Override

    5.    public void configure(WebSecurity web) throws Exception {

    6.        web

    7.            .ignoring()

    8.            .antMatchers("/resources/**");

    9.    }

    10. }

    以筆者的經驗,這個配置中並不會出現太多的配置信息。

    AuthenticationManagerBuilder

    1. @Configuration

    2. @EnableWebSecurity

    3. public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    4.    @Override

    5.    protected void configure(AuthenticationManagerBuilder auth) throws Exception {

    6.        auth

    7.            .inMemoryAuthentication()

    8.            .withUser("admin").password("admin").roles("USER");

    9.    }

    10. }

    想要在WebSecurityConfigurerAdapter中進行認證相關的配置,可以使用configure(AuthenticationManagerBuilder auth)暴露一個AuthenticationManager的建造器:AuthenticationManagerBuilder 。如上所示,我們便完成了記憶體中用戶的配置。

    細心的朋友會發現,在前面的文章中我們配置記憶體中的用戶時,似乎不是這麼配置的,而是:

    1. @Configuration

    2. @EnableWebSecurity

    3. public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    4.    @Autowired

    5.    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {

    6.        auth

    7.            .inMemoryAuthentication()

    8.                .withUser("admin").password("admin").roles("USER");

    9.    }

    10. }

    如果你的應用只有唯一一個WebSecurityConfigurerAdapter,那麼他們之間的差距可以被忽略,從方法名可以看出兩者的區別:使用@Autowired註入的AuthenticationManagerBuilder是全域性的身份認證器,作用域可以跨越多個WebSecurityConfigurerAdapter,以及影響到基於Method的安全控制;而 protectedconfigure()的方式則類似於一個匿名內部類,它的作用域局限於一個WebSecurityConfigurerAdapter內部。關於這一點的區別,可以參考我曾經提出的issue:spring-security#issues4571。官方文件中,也給出了配置多個WebSecurityConfigurerAdapter的場景以及demo,將在該系列的後續文章中解讀。

    赞(0)

    分享創造快樂

    © 2020 知識星球   网站地图