Spring Security修煉手冊(一)————初識Security

    在之前作東西的時候,對於認證鑑權的框架技術選型,一般使用Apache Shiro,多是接觸比較早,感受用起來比較方便的緣由,知道最近接了一個好大好大的項目分佈式應用+大數據數據庫+私有IaaS雲+PaaS,埋頭苦學一星期,算是吃透了Spring Security的一半,那麼一是爲了記錄在學習過程當中的知識點,二是爲了讓沒有接觸過安全框架,或者還在使用數據庫,本身寫Filter比較原始方式作權限控制的朋友提供一個學習的參考。那麼廢話不說太多,下面開始一步一步來。html

  1、初識Spring Security

        首先看名字就能夠看出來,這個框架出自於Pivotal 的Spring系列。Spring Security 提供了基於javaEE的企業應用,全面的安全服務。 你們使用Spring Secruity的緣由有不少,可是大部分都是發現了因爲javaEE的Servlet規範或EJB規範中的安全功能缺少典型企業應用場景所需的深度。 那麼Security提供的 「認證」和「受權」(或者訪問控制) 是整個框架也是本系列博客所要講解的重要內容。java

2、引入Security依賴

    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'
}

3、Security的基本認證功能的使用

    首先明確一個事情,Spring Security全部提供給開發者的認證和鑑權功能都是基於過濾器鏈的,而我看到的大部分講解Security的博客和資料中,卻不多說起每一個功能做用的過濾器是誰?過濾器的執行流程是怎麼樣的!我以前在學習Docker和K8S的時候買的一本書講解的很是透徹,做者不只僅在講怎麼用!而是從:是什麼?怎麼用?爲何?這三方面來講,所以我會在文中經過Debug或流程圖,爲你們深刻的講解這款框架的東西。安全

    3.一、HttpBasic認證

        那麼當你引入了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,經過生成的默認密碼進行認證,不過這種方式基本不太會使用,不着重介紹。

    3.二、表單認證

        表單認證是大部分業務場景中都須要使用的一種認證方式,那麼如何配置,又有哪些可配置的呢?看以下代碼:

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防禦功能關掉哦,不然你講沒法進行認證。

4、基於Spring的配置

    那麼經過以上代碼的講解,你應該對於認證功能的基本使用有了必定的瞭解,可是上面的代碼中有一個開發界很是難以容忍的問題,就是含有大量的硬編碼!!!那麼咱們如何解決的?

首先咱們建立三個類,分別叫: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是因爲我根本沒寫這個頁面,但已經能夠證實咱們的配置生效,避免了硬編碼的問題

 在下一篇博客裏,我會介紹自定義身份認證和一些處理器的用法及源碼,敬請關注!

相關文章
相關標籤/搜索