在之前作東西的時候,對於認證鑑權的框架技術選型,一般使用Apache Shiro,多是接觸比較早,感受用起來比較方便的緣由,知道最近接了一個好大好大的項目分佈式應用+大數據數據庫+私有IaaS雲+PaaS,埋頭苦學一星期,算是吃透了Spring Security的一半,那麼一是爲了記錄在學習過程當中的知識點,二是爲了讓沒有接觸過安全框架,或者還在使用數據庫,本身寫Filter比較原始方式作權限控制的朋友提供一個學習的參考。那麼廢話不說太多,下面開始一步一步來。html
首先看名字就能夠看出來,這個框架出自於Pivotal 的Spring系列。Spring Security 提供了基於javaEE的企業應用,全面的安全服務。 你們使用Spring Secruity的緣由有不少,可是大部分都是發現了因爲javaEE的Servlet規範或EJB規範中的安全功能缺少典型企業應用場景所需的深度。 那麼Security提供的 「認證」和「受權」(或者訪問控制) 是整個框架也是本系列博客所要講解的重要內容。java
Security官方連接:https://projects.spring.io/spring-security/web
打開你的IED,在Maven座標以下:想使用其餘版本請去如上連接,若是你以前接觸過Spring IO那麼無需指定Version.spring
<dependencies> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> <version>5.0.5.RELEASE</version> </dependency> </dependencies>
Gradle以下:數據庫
dependencies { compile 'org.springframework.security:spring-security-web:5.0.5.RELEASE' }
首先明確一個事情,Spring Security全部提供給開發者的認證和鑑權功能都是基於過濾器鏈的,而我看到的大部分講解Security的博客和資料中,卻不多說起每一個功能做用的過濾器是誰?過濾器的執行流程是怎麼樣的!我以前在學習Docker和K8S的時候買的一本書講解的很是透徹,做者不只僅在講怎麼用!而是從:是什麼?怎麼用?爲何?這三方面來講,所以我會在文中經過Debug或流程圖,爲你們深刻的講解這款框架的東西。安全
那麼當你引入了Security的依賴後,無需作其餘任何的事情,啓動項目,訪問的時候你就會發現你的應用已經有了一個基本的認證功能,其實前面說的話不是徹底正確的,因爲筆者以前使用的Spring Boot版本爲1.5,依賴的Security 4.X版本,因此無需任何配置,啓動項目訪問則會彈出默認的httpbasic認證,那麼本次Demo是基於security5.X ,Spring Boot2.X版本去作的,通過我翻閱官方文檔和Spring Boot2.X的properties,在這個5.X的版本中已經將默認的認證方式更改成表單認證,而且security.basic.enabled屬性一樣是過時了的。框架
下面的圖是官方給出的屬性配置,已經無security.basic.enabled分佈式
在這裏筆者十分負責任的說,若是想開啓httpbasic認證,須要在配置類中進行配置才能夠,親測經過properties配置不生效,開啓httpbasic認證的代碼以下:ide
import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter ; @Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter{ @Override protected void configure(HttpSecurity http) throws Exception { http .httpBasic()//開啓httpbasic認證 .and() .authorizeRequests()//Security表達式 .anyRequest().authenticated();//全部請求都須要認證 } }
啓動項目,在啓動的時候會發現控制檯有以下輸出,這個字符串就是Security默認生成的認證密碼。學習
訪問應用,彈出httpbasic,經過生成的默認密碼進行認證,不過這種方式基本不太會使用,不着重介紹。
表單認證是大部分業務場景中都須要使用的一種認證方式,那麼如何配置,又有哪些可配置的呢?看以下代碼:
import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurer Adapter; @Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter{ @Override protected void configure(HttpSecurity http) throws Exception { http .formLogin() .loginPage("/loginPage.html")//用戶未認證時,轉跳到認證的頁面 .loginProcessingUrl("/toLogin")//form中action的地址,也就是處理認證請求的URL .usernameParameter("UM")//form中用戶名密碼的name名 .passwordParameter("PW") .defaultSuccessUrl("/index")//認證成功後默認轉跳的URL .and() .authorizeRequests() .antMatchers("/loginPage.html","/toLogin").permitAll()//最後不要忘記將自定義的 //如上不須要認證的URL加進來 .anyRequest().authenticated(); } }
咱們訪問任意須要認證的URL,發現會自動轉跳到配置的認證頁面。
咱們暫時先使用內存用戶,在properties中配置一個admin用戶,模擬登陸。
登錄後,自動轉跳到index的controller中,對了!若是你使用了本身的登陸頁面,記得將CSRF防禦功能關掉哦,不然你講沒法進行認證。
那麼經過以上代碼的講解,你應該對於認證功能的基本使用有了必定的瞭解,可是上面的代碼中有一個開發界很是難以容忍的問題,就是含有大量的硬編碼!!!那麼咱們如何解決的?
首先咱們建立三個類,分別叫:SecurityProperties、ToLoginProperties、LoginProperties,代碼分別以下:
public class LoginProperties { private String loginPage = "/loginPage.html"; private String loginProcessingUrl = "/toLogin"; private String usernameParameter = "UM"; private String passwordParameter = "PW"; private String defaultSuccessUrl = "/index"; public String getLoginPage() { return loginPage; } public void setLoginPage(String loginPage) { this.loginPage = loginPage; } public String getLoginProcessingUrl() { return loginProcessingUrl; } public void setLoginProcessingUrl(String loginProcessingUrl) { this.loginProcessingUrl = loginProcessingUrl; } public String getUsernameParameter() { return usernameParameter; } public void setUsernameParameter(String usernameParameter) { this.usernameParameter = usernameParameter; } public String getPasswordParameter() { return passwordParameter; } public void setPasswordParameter(String passwordParameter) { this.passwordParameter = passwordParameter; } public String getDefaultSuccessUrl() { return defaultSuccessUrl; } public void setDefaultSuccessUrl(String defaultSuccessUrl) { this.defaultSuccessUrl = defaultSuccessUrl; } }
public class ToLoginProperties { private LoginProperties loginProperties = new LoginProperties(); public LoginProperties getLoginProperties() { return loginProperties; } public void setLoginProperties(LoginProperties loginProperties) { this.loginProperties = loginProperties; } }
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; @Component @ConfigurationProperties(prefix = "jy.security") public class SecurityProperties { private ToLoginProperties toLoginProperties = new ToLoginProperties(); public ToLoginProperties getToLoginProperties() { return toLoginProperties; } public void setToLoginProperties(ToLoginProperties toLoginProperties) { this.toLoginProperties = toLoginProperties; } }
經過以上代碼,咱們就能夠讀取到配置文件中,以「jy.security」開頭的屬性,並將屬性對應的值注入到其中,這樣當咱們配置了對應屬性的時候,值即被替換,未配置的時候則走咱們的默認值。
而後咱們把securityconfig類在修改一下,不在使用硬編碼,而是將SecurityProperties類注入。
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import com.spring.demo.peoperties.SecurityProperties; @Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter{ @Autowired private SecurityProperties securityProperties; @Override protected void configure(HttpSecurity http) throws Exception { http .formLogin() .loginPage(securityProperties.getToLoginProperties().getLoginProperties().getLoginPage())//用戶未認證時,轉跳到認證的頁面 .loginProcessingUrl(securityProperties.getToLoginProperties().getLoginProperties().getLoginProcessingUrl())//form中action的地址,也就是處理認證請求的URL .usernameParameter(securityProperties.getToLoginProperties().getLoginProperties().getUsernameParameter())//form中用戶名密碼的name名 .passwordParameter(securityProperties.getToLoginProperties().getLoginProperties().getPasswordParameter()) .defaultSuccessUrl(securityProperties.getToLoginProperties().getLoginProperties().getDefaultSuccessUrl())//認證成功後默認轉跳的URL .and() .authorizeRequests() .antMatchers(securityProperties.getToLoginProperties().getLoginProperties().getLoginPage(), securityProperties.getToLoginProperties().getLoginProperties().getLoginProcessingUrl()).permitAll() .anyRequest().authenticated() .and() .csrf().disable() ; } }
最後咱們作一個測試,證實經過配置文件的方式,能夠對咱們的配置類修改,咱們修改未認證時轉跳的認證頁面的URL爲「/loginTest」
重啓項目,訪問/index,結果以下:404是因爲我根本沒寫這個頁面,但已經能夠證實咱們的配置生效,避免了硬編碼的問題
在下一篇博客裏,我會介紹自定義身份認證和一些處理器的用法及源碼,敬請關注!