1. 程式人生 > >Spring Boot(五):Spring Boot 整合 Spring Security (I)

Spring Boot(五):Spring Boot 整合 Spring Security (I)

1. 新增Maven依賴

在pom.xml引用spring security.

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-security</artifactId>
</dependency>

新增Maven依賴後,執行專案,訪問https://localhost:8443/SpringBootBase/ 瀏覽器會彈出如下身份驗證框:

如圖1所示:

image

這是因為Spring Security對我們的工程預設使用"basic"身份認證,只要引入了Spring Security, 那麼整個web應用都是安全的,所有資源訪問都要經過身份驗證授權才可以訪問。可用user 及 隨機密碼登入,隨機密碼可從web應用啟動日誌查詢, 如:

Using default security password: 89c19869-277c-4eba-89c8-590e0405ae84

當然也可以在application.properties裡自定義username和password.

security.user.name=admin
security.user.password=123456

或者直接關閉這個預設的basic認證

security.basic.enabled=false

當你客製化自己的授權體系後,這個預設的"basic"認證將會自動被替代。

2. 配置spring security

我們還是以上一篇部落格的工程程式碼為基礎來整合Spring Security.

  • index.html: 登入介面
<!DOCTYPE html>
<html lang="zh-cn" xmlns:th="http://www.thymeleaf.org">
<head>
	<meta charset="utf-8"/>
	
	<title>Login</title>
	
	<link rel="stylesheet" th:href="@{css/bootstrap.min.css}"/>
	<link rel="stylesheet" th:href="@{css/customer/login.css}"
/>
</head> <body> <div class="container"> <h3 align="center">這是一個帶有登入框的主頁</h3> <form class="form-signin" th:action="@{/login}" th:object="${user}" method="post"> <h2 class="form-signin-heading">請 登 錄</h2> <input type="text" class="form-control" placeholder="賬號" th:field="*{username}"/> <input type="password" class="form-control" placeholder="密碼" th:field="*{password}"/> <p th:if="${param.logout}" class="error-code">已成功登出</p> <p th:if="${param.error}" class="error-code">使用者名稱或者密碼錯誤</p> <button class="btn btn-lg btn-primary btn-block" type="submit">登入</button> </form> </div> </body> </html>

這回我們新增了兩行程式碼:

<p th:if="${param.logout}" class="error-code">已成功登出</p>
<p th:if="${param.error}" class="error-code">使用者名稱或者密碼錯誤</p>

其中th:if="${param.logout}" 為Thymeleaf模板引擎判斷語法,表示如果http post/get 請求的引數中帶有logout,則顯示已成功登出。

  • 再增加一個登入成功的歡迎介面welcome.html,帶有登出按鈕。
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
    <head>
    	<meta charset="utf-8"/>
        <title>Hello World!</title>
    </head>
    <body>
        <h1 th:inline="text">Hello [[${#httpServletRequest.remoteUser}]]!</h1>
        <form th:action="@{/logout}" method="post">
            <input type="submit" value="注 銷"/>
        </form>
    </body>
</html>

th:inline="text"表示文字內聯,即取${#httpServletRequest.remoteUser}值作為文字顯示。

  • 在LoginController.java裡新增兩個controller
@RequestMapping(value ="/welcome", method = RequestMethod.GET)
String welcome() {
  return "welcome";
}

@RequestMapping(value ="/login", method = RequestMethod.GET)
String login(Model model, UserVO user) {
  model.addAttribute("user", user);
  return "index";
}

一個是用來welcome跳轉,一個是用來login頁面跳轉。

  • 定製安全策略

接下來寫個類WebSecurityConfig來繼承WebSecurityConfigurerAdapter,用於確保經過認證的使用者才能訪問我們設定的需要經過驗證的url.

package tech.onroad.springbootbase.auth;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{

	@Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
            .withUser("admin").password("123456").roles("USER");
    }


    @Override
    protected void configure(HttpSecurity http) throws Exception {
    	http
	        .authorizeRequests()
	            .antMatchers("/").permitAll()
	            .anyRequest().authenticated()
	            .and()
	        .formLogin()
	            .loginPage("/login")
	            .defaultSuccessUrl("/welcome")
	            .permitAll()
	            .and()
	        .logout()
	            .permitAll();
    }
    
    @Override
    public void configure(WebSecurity web) throws Exception {
        //解決靜態資源被攔截的問題
        web.ignoring().antMatchers("/css/**");
    }
}
auth.inMemoryAuthentication()
            .withUser("admin").password("123456").roles("USER");

表示在記憶體中建立一個username為admin, password為123456,role為USER的使用者。但大多數web應用肯定會有自己的使用者管理系統,這個我們在接下來的部落格會另起一篇部落格介紹,這裡先用記憶體使用者。

注意:前臺login表單傳過來的賬戶名及密碼的引數名必須為username和password,否則Spring Security無法正確獲取使用者名稱及密碼與後臺使用者系統進行匹配,具體原因是Sping Security的預設定義使用者系統的使用者名稱和密碼為username和password. 如果想詳細瞭解一下為什麼,可參考auth.inMemoryAuthentication().withUser(“admin”).password(“123456”).roles(“USER”)原始碼。

configure(HttpSecurity http)方法是用來定義安全策略,如哪些url路徑需要經過授權才能訪問,哪些不用。如上面的程式碼中,"/"就不需要授權就可以訪問,即我們可以正常訪問https://localhost:8443/SpringBootBase/,而不需要使用者授權。

當一個使用者成功登入後,即Spring Security認證成功後,我們的web應用將重定向到之前使用者請求的頁面,也可以客製化,使用defaultSuccessUrl方法將其重定向到指定頁面。loginPage("/login")表示在沒有授權前,任何訪問需要授權才能訪問的頁面都會先跳轉到/login登入頁面。

web.ignoring().antMatchers("/css/**");表示所以css目錄下的靜態資源都不作攔截。

3. 驗證

按照程式碼邏輯:我們訪問https://localhost:8443/SpringBootBase/,首先會跳轉到index.html介面(因為https://localhost:8443/SpringBootBase/和https://localhost:8443/SpringBootBase/index.html是一樣的),然後輸入賬戶名admin及密碼123456,點選登入,將使用者名稱及密碼傳到後臺進行匹配,如果成功,則跳轉到welcome.html介面,如果失敗,則會預設指向/login?error,而從LoginController, 又將其定向到index.html頁面,提示使用者名稱或者密碼錯誤。點選welcome介面登出按鈕,則會預設跳轉到/login?logout, 所以又回到index.html頁面,顯示已成功登出。

我們來執行一下,看結果是不是一樣的?

  1. 訪問https://localhost:8443/SpringBootBase/, 如圖2所示

image

  1. 輸入admin及密碼123456,點選登入,成功跳轉到welcome介面,如圖3所示

image

  1. 點選登出登出,如圖4所示

image

  1. 輸入錯誤的賬戶名或密碼,則得圖5結果

image

一切如我們預期執行,說明我們spring security整合成功了。當然,這隻用了spring security最簡單的功能,還有自定義使用者系統等等,我們接下來會慢慢介紹。