Spring Security-配置


完成了基本配置后,我們需要自定義Spring Security的一些進階配置,才能應用於我們的項目。

和SpringBoot項目中其他插件一樣,我們一般也是寫一個配置類來存放對Spring Security的配置。

@EnableWebSecurity

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

@Import({ WebSecurityConfiguration.class, // <2>
      SpringWebMvcImportSelector.class }) // <1>
@EnableGlobalAuthentication // <3>
@Configuration
public @interface EnableWebSecurity {
   boolean debug() default false;
}

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

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

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

<3> @EnableGlobalAuthentication 注解的源碼如下:

@Import(AuthenticationConfiguration.class)
@Configuration
public @interface EnableGlobalAuthentication {
}

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

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

WebSecurityConfigurerAdapter

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

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

配置SecurityConfig

在項目源代碼目錄下建立config包,創建 SecurityConfig 配置類,繼承 WebSecurityConfigurerAdapter 抽象類,實現 Spring Security 在 Web 場景下的自定義配置。

重寫configure(AuthenticationManagerBuilder auth)

想要在 WebSecurityConfigurerAdapter 中進行認證相關的配置,可以使用 configure(AuthenticationManagerBuilder auth) 暴露一個 AuthenticationManager 的建造器:AuthenticationManagerBuilder 如下所示:

// SecurityConfig.java

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.
            // <X> 使用內存中的 InMemoryUserDetailsManager
            inMemoryAuthentication()
            // <Y> 不使用 PasswordEncoder 密碼編碼器
            .passwordEncoder(NoOpPasswordEncoder.getInstance())
            // <Z> 配置 admin 用戶
            .withUser("admin").password("admin").roles("ADMIN")
            // <Z> 配置 normal 用戶
            .and().withUser("normal").password("normal").roles("NORMAL");
}

說明

處,調用 AuthenticationManagerBuilder#inMemoryAuthentication() 方法,使用內存級別的 InMemoryUserDetailsManager Bean 對象,提供認證的用戶信息。

Spring 內置了兩種 UserDetailsManager 實現:

  1. InMemoryUserDetailsManager
  2. JdbcUserDetailsManager ,基於 JDBC的 JdbcUserDetailsManager 。

實際項目中,我們更多采用調用AuthenticationManagerBuilder#userDetailsService(userDetailsService) 方法,使用自定義實現的 UserDetailsService 實現類,更加靈活、自由地實現認證的用戶信息的讀取。

處,調用 AbstractDaoAuthenticationConfigurer#passwordEncoder(passwordEncoder) 方法,設置 PasswordEncoder 密碼編碼器。在這里,為了方便,我們使用 NoOpPasswordEncoder 。實際上,等於不使用 PasswordEncoder 。 NoOpPasswordEncoderencode方法就只是簡單地把字符序列轉成字符串,也就是說,你輸入的密碼”123456”存儲在數據庫里仍然是”123456”,這樣如果數據庫被攻破的話,密碼就直接泄露了,十分不安全。

不過,正因其十分簡單,所以在Spring Security 5.0 之前NoOpPasswordEncoder是作為默認的密碼編碼器而存在的,它可以是你沒有主動加密時的一個默認選擇。

生產環境下,推薦使用 BCryptPasswordEncoder 。更多關於 PasswordEncoder 的內容,推薦閱讀《該如何設計你的 PasswordEncoder?》文章。

處,配置了「admin/admin」和「normal/normal」兩個用戶,分別對應 ADMIN 和 NORMAL 角色。還可以配置更多的用戶。

重寫configure(HttpSecurity http)

然后,我們重寫 configure(HttpSecurity http) 方法,主要配置 URL 的權限控制。

@Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers("test/demo").permitAll()
                // 配置請求地址的權限
                .antMatchers("test/admin").hasRole("ADMIN")
                .antMatchers("test/normal").hasRole("NORMAL")
                .anyRequest().authenticated()
                // 設置 Form 表單登陸
                .and().formLogin()
            	//loginPage("/login")
            	.permitAll()
                .and().logout()
            	//logoutUrl("/logout")
            	.permitAll();
    }

上述是一個使用 Java Configuration 配置 HttpSecurity 的典型配置,其中 http 作為根開始配置,每一個 and()對應了一個模塊的配置(等同於 xml 配置中的結束標簽),並且 and() 返回了 HttpSecurity 本身,於是可以連續進行配置。(鏈式編程調用)

他們配置的含義也非常容易通過變量本身來推測,

  • authorizeRequests() 配置路徑攔截,表明路徑訪問所對應的權限,角色,認證信息。
  • formLogin() 對應表單認證相關的配置
  • logout() 對應了注銷相關的配置
  • httpBasic() 可以配置 basic 登錄
  • etc

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

這里要特別注意:如果配置了loginPage和logoutUrl這兩項,就必須提供html文件來構成 登陸頁面,否則就會無法登錄。所以這里不配置這兩項,還是使用系統默認給的登陸頁面。

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

調用 HttpSecurity.authorizeRequests() 方法,開始配置 URL 的權限控制

下面,是配置權限控制會使用到的方法:

  • #String... antPatterns) 方法,配置匹配的 URL 地址,基於 Ant 風格路徑表達式 ,可傳入多個。
  • 【常用】permitAll() 方法,所有用戶可訪問。
  • 【常用】denyAll() 方法,所有用戶不可訪問。
  • 【常用】authenticated() 方法,登錄用戶可訪問。
  • anonymous() 方法,無需登錄,即匿名用戶可訪問。
  • rememberMe() 方法,通過 remember me 登錄的用戶可訪問。
  • fullyAuthenticated() 方法,非 remember me 登錄的用戶可訪問。
  • hasIpAddress(String ipaddressExpression) 方法,來自指定 IP 表達式的用戶可訪問。
  • 【常用】hasRole(String role) 方法, 擁有指定角色的用戶可訪問。
  • 【常用】hasAnyRole(String... roles) 方法,擁有指定任一角色的用戶可訪問。
  • 【常用】hasAuthority(String authority) 方法,擁有指定權限(authority)的用戶可訪問。
  • 【常用】hasAuthority(String... authorities) 方法,擁有指定任一權限(authority)的用戶可訪問。
  • 【最牛】access(String attribute) 方法,當 Spring EL 表達式的執行結果為 true 時,可以訪問。

@PermitAll 注解,等價於 permitAll() 方法,所有用戶可訪問。

重要!!!因為在SecurityConfig中,配置了 .anyRequest().authenticated() ,任何請求,訪問的用戶都需要經過認證。所以這里 @PermitAll 注解實際是不生效的

也就是說,Java Config 配置的權限,和注解配置的權限,兩者是疊加的。

@PreAuthorize 注解,等價於 access(String attribute) 方法,,當 Spring EL 表達式的執行結果為 true 時,可以訪問。

重寫configure(WebSecurity web)

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    public void configure(WebSecurity web) throws Exception {
        web
            .ignoring()
            .antMatchers("/resources/**");
    }
}

這個方法看起來不是太常用……


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM