基本上每一個項目都會有用戶登錄的這個功能,用戶需要在登錄之後才能夠去訪問一些資源,如果沒登錄的話就不能訪問(403)。我們可以自己編碼去實現這樣的業務邏輯,當然每一次都自己去編碼是比較耗時的,畢竟市面上已經有現成的開源的框架可以拿來使用了(Apache的shiro與Spring的Spring Security)
,這一篇的博客的主角就是介紹一下後者在SpringBoot中的整合配置,以及如何基本使用
首先還是一樣,要用到什麼技術,就引入什麼技術的maven依賴:
<!-- 引入security-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
同時因爲後面還要用到thymeleaf
模版引擎,所以我們順便把thymeleaf
也導入了:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
像shiro、Springsecurity
這些框架技術都統稱爲安全框架,安全框架有兩個重要的作用,是認證和授權。認證是程序確認你是什麼身份,而授權就是程序根據你的身份給你不同的權利。
這裏不講空話,用我看的學習資源裏面的一個場景,一個武林祕籍系統,用戶可以根據不同的權限從而查看到不同的武林祕籍,這是初始的樣子:
我們現在需要做的是點進去每個祕籍,需要不同的身份,比如我是普通的用戶,那麼我只能去查看普通的武林祕籍,同理,另外兩個也是一樣,而且,當我們登錄之後會去顯示出用戶的信息和所擁有的身份。
這時就可以用到springsecurity
了,我們需要創建一個SpringSecurity的配置類,讓其繼承於WebSecurityConfigurerAdapter
,並實現一些方法:
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@EnableWebSecurity
註解的作用是開啓security的服務(有點廢話),它內部也是個組合註解,有一個@Configuration
,可以理解爲通知SpringBoot讓其掃描到該類。
之後看看讓其繼承兩個方法,爲什麼是兩個呢,一個是認證,另外一個是授權啦:
//授權
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/").permitAll()
.antMatchers("/level1/**").hasRole("VIP1") //普通武林祕籍,並設置所需身份爲VIP1
.antMatchers("/level2/**").hasRole("VIP2") //高級武功祕籍,並設置所需身份爲VIP2
.antMatchers("/level3/**").hasRole("VIP3"); //爵士武功祕籍,並設置所需身份爲VIP3
//自動配置登錄,使用這行代碼之後,springsecurity會幫我們生成一個登錄,並自動幫我們校驗用戶名和密碼!,默認的路徑爲/login
http.formLogin();
//自動配置註銷,可以通過訪問路徑/logout,來幫我們註銷當前用戶,底層原理是撤銷相關的session
http.logout().logoutSuccessUrl("/");
//自動配置記住我功能,就像是很多網站的"記住我"功能,使用這個後,下次進入網站無需登錄,底層原理是像瀏覽器發送一個cookie信息,內容是一個sessionid,有效期14天,這樣下次訪問時帶上這個sessionid就能找到session了
http.rememberMe();
}
//認證
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//這裏爲了簡便,就不從數據庫中換取數據了,從內存中獲取,inMemoryAuthentication()就是從內存中獲取,這裏分別設置了兩個用戶,它們的身份分別是"VIP1"、"VIP2"和"VIP3",用戶名和密碼見具體方法。
auth.inMemoryAuthentication().passwordEncoder(NoOpPasswordEncoder.getInstance()).withUser("leslie").password("123").roles("VIP1","VIP2")
.and()
.withUser("lion").password("123").roles("VIP3");
}
每一行代碼的作用寫在註釋中。總結下,到這一步,我們做完的事情有給leslie
和lion
的兩個用戶授權VIP1、VIP2和VIP3的身份,併爲不同的訪問路徑授權了不同的用戶。
配置類寫完之後,還不夠,這裏controller
代碼略過了,無非就是控制頁面跳轉到哪裏。前端頁面代碼也是需要修改了,修改之前需要引入thymeleaf-springsecurity
的整合:
<!-- 引入thymeleaf與spring security整合-->
<!-- https://mvnrepository.com/artifact/org.thymeleaf.extras/thymeleaf-extras-springsecurity5 -->
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>
修改後的前端代碼:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1 align="center">歡迎光臨武林祕籍管理系統</h1>
<div sec:authorize="!isAuthenticated()">
<h2 align="center">遊客您好,如果想查看武林祕籍 <a th:href="@{/login}">請登錄</a></h2>
</div>
<div sec:authorize="isAuthenticated()">
<h2 align="center"><span sec:authentication="name"></span>您好,你的角色是:<span sec:authentication="principal.authorities"></span></h2>
<form method="post" th:action="@{/logout}">
<input type="submit" value="註銷"/>
</form>
</div>
<hr>
<div sec:authorize="hasRole('VIP1')">
<h3>普通武功祕籍</h3>
<ul>
<li><a th:href="@{/level1/1}">羅漢拳</a></li>
<li><a th:href="@{/level1/2}">武當長拳</a></li>
<li><a th:href="@{/level1/3}">全真劍法</a></li>
</ul>
</div>
<div sec:authorize="hasRole('VIP2')">
<h3>高級武功祕籍</h3>
<ul>
<li><a th:href="@{/level2/1}">太極拳</a></li>
<li><a th:href="@{/level2/2}">七傷拳</a></li>
<li><a th:href="@{/level2/3}">梯雲縱</a></li>
</ul>
</div>
<div sec:authorize="hasRole('VIP3')">
<h3>絕世武功祕籍</h3>
<ul>
<li><a th:href="@{/level3/1}">葵花寶典</a></li>
<li><a th:href="@{/level3/2}">龜派氣功</a></li>
<li><a th:href="@{/level3/3}">獨孤九劍</a></li>
</ul>
</div>
</body>
</html>
這裏說明一下,添加一些代碼的作用
頁面首先需要引入thymeleaf
的約束空間:
xmlns:sec="http://www.thymeleaf.org/extras/spring-security"
引入之後就可以使用一些和springsecurity
有關的標籤了。
- sec:authentication=“name”:表示取出當前登錄的用戶名。
- sec:authentication=“principal.authorities”:取出當前用戶的所有身份
- sec:authorize=“isAuthenticated()”:判斷當前狀態是否登錄,同理屬性內前面加一個!表示判斷是否未登錄,有這個之後,我們以後就不需要自己編寫攔截器判斷判斷登錄狀態了。
- sec:authorize=“hasRole(‘VIP3’)”:判斷當前登錄用戶是否有該身份。
之後我們再次查看該頁面:
可以看到 sec:authorize=“isAuthenticated()” 的作用出來了,如果未登錄的話,只顯示這個,點擊登錄,看看Springsecurity爲我們生成的登錄頁面:
還挺好看的,下面的那個單選框"Remember me on this computer"是之前http.rememberMe();
所自動配置的功能。首先登錄leslie
,看看能否顯示前兩個級別的武功祕籍:
成功,點擊註銷(剛剛http.logout()
的作用),再換成lion
用戶試試,看看能否顯示絕世武功祕籍:
簡單記錄到這裏,由於springsecurity
的具體知識我也還沒有學過,覺得挺方便的,之後找機會補完這方面的知識,再着重記錄。