今天我們將在上一篇博客《Spring Boot(四):Spring Boot 集成 Thymeleaf》的基礎(chǔ)上來集成Spring Security.
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所示:

這是因為Spring Security對我們的工程默認(rèn)使用"basic"身份認(rèn)證,只要引入了Spring Security, 那么整個web應(yīng)用都是安全的,所有資源訪問都要經(jīng)過身份驗證授權(quán)才可以訪問。可用user 及 隨機(jī)密碼登錄,隨機(jī)密碼可從web應(yīng)用啟動日志查詢, 如:
Using default security password: 89c19869-277c-4eba-89c8-590e0405ae84
當(dāng)然也可以在application.properties里自定義username和password.
security.user.name=admin
security.user.password=123456
或者直接關(guān)閉這個默認(rèn)的basic認(rèn)證
security.basic.enabled=false
詳情請參考官方文檔:https://docs.spring.io/spring-boot/docs/1.5.9.RELEASE/reference/html/boot-features-security.html
當(dāng)你客制化自己的授權(quán)體系后,這個默認(rèn)的"basic"認(rèn)證將會自動被替代。
2. 配置spring security
我們還是以上一篇博客的工程代碼為基礎(chǔ)來整合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 請求的參數(shù)中帶有l(wèi)ogout,則顯示已成功注銷。
- 再增加一個登錄成功的歡迎界面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"表示文本內(nèi)聯(lián),即取${#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跳轉(zhuǎn),一個是用來login頁面跳轉(zhuǎn)。
- 定制安全策略
接下來寫個類WebSecurityConfig來繼承WebSecurityConfigurerAdapter,用于確保經(jīng)過認(rèn)證的用戶才能訪問我們設(shè)置的需要經(jīng)過驗證的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 {
//解決靜態(tài)資源被攔截的問題
web.ignoring().antMatchers("/css/**");
}
}
auth.inMemoryAuthentication()
.withUser("admin").password("123456").roles("USER");
表示在內(nèi)存中創(chuàng)建一個username為admin, password為123456,role為USER的用戶。但大多數(shù)web應(yīng)用肯定會有自己的用戶管理系統(tǒng),這個我們在接下來的博客會另起一篇博客介紹,這里先用內(nèi)存用戶。
注意:前臺login表單傳過來的賬戶名及密碼的參數(shù)名必須為username和password,否則Spring Security無法正確獲取用戶名及密碼與后臺用戶系統(tǒng)進(jìn)行匹配,具體原因是Sping Security的默認(rèn)定義用戶系統(tǒng)的用戶名和密碼為username和password. 如果想詳細(xì)了解一下為什么,可參考auth.inMemoryAuthentication().withUser("admin").password("123456").roles("USER")源碼。
configure(HttpSecurity http)方法是用來定義安全策略,如哪些url路徑需要經(jīng)過授權(quán)才能訪問,哪些不用。如上面的代碼中,"/"就不需要授權(quán)就可以訪問,即我們可以正常訪問https://localhost:8443/SpringBootBase/,而不需要用戶授權(quán)。
當(dāng)一個用戶成功登錄后,即Spring Security認(rèn)證成功后,我們的web應(yīng)用將重定向到之前用戶請求的頁面,也可以客制化,使用defaultSuccessUrl方法將其重定向到指定頁面。loginPage("/login")表示在沒有授權(quán)前,任何訪問需要授權(quán)才能訪問的頁面都會先跳轉(zhuǎn)到/login登錄頁面。
web.ignoring().antMatchers("/css/**");表示所以css目錄下的靜態(tài)資源都不作攔截。
3. 驗證
按照代碼邏輯:我們訪問https://localhost:8443/SpringBootBase/,首先會跳轉(zhuǎn)到index.html界面(因為https://localhost:8443/SpringBootBase/和https://localhost:8443/SpringBootBase/index.html是一樣的),然后輸入賬戶名admin及密碼123456,點擊登錄,將用戶名及密碼傳到后臺進(jìn)行匹配,如果成功,則跳轉(zhuǎn)到welcome.html界面,如果失敗,則會默認(rèn)指向/login?error,而從LoginController, 又將其定向到index.html頁面,提示用戶名或者密碼錯誤。點擊welcome界面注銷按鈕,則會默認(rèn)跳轉(zhuǎn)到/login?logout, 所以又回到index.html頁面,顯示已成功注銷。
我們來運行一下,看結(jié)果是不是一樣的?
-
訪問https://localhost:8443/SpringBootBase/, 如圖2所示
圖2 -
輸入admin及密碼123456,點擊登錄,成功跳轉(zhuǎn)到welcome界面,如圖3所示
圖3 -
點擊注銷登出,如圖4所示
圖4 -
輸入錯誤的賬戶名或密碼,則得圖5結(jié)果
圖5
一切如我們預(yù)期執(zhí)行,說明我們spring security集成成功了。當(dāng)然,這只用了spring security最簡單的功能,還有自定義用戶系統(tǒng)等等,我們接下來會慢慢介紹。
完整代碼可到我的github下載:
https://github.com/onroadtech/SpringbootBase/
branch: master
commit-id: 2872ee008f23197b5fa28acee95aae378d4d1f01
本博文已同步發(fā)表于我的個人博客網(wǎng)站,歡迎轉(zhuǎn)載指正并注明出處。
個人博客: www.onroad.tech
指正郵箱: onroad_tech@163.com



