手摸手教你定制 Spring Security 表單登錄
在本專欄前篇文章中介紹了HttpBasic模式,該模式比較簡單,只是進行了通過攜帶Http的Header進行簡單的登錄驗證,而且沒有可以定制的登錄頁面,所以使用場景比較窄。
對于一個完整的應用系統(tǒng),與登錄驗證相關的頁面都是高度定制化的,非常美觀而且提供多種登錄方式。這就需要Spring Security支持我們自己定制登錄頁面,也就是本文給大家介紹的FormLogin模式登錄認證模式。
1. 新建項目
在介紹相關內(nèi)容之前,需要先搭建一個demo,新建一個項目spring-security-02,需要添加依賴如下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
除此之外其實還需要添加web、thymeleaf的依賴,這里就不在貼出來了。
demo結構如下:
2. 新建登錄頁面
這里不再使用Security默認的頁面,自己定制一個,代碼如下:
單純的一個表單登錄頁面,需要注意以下幾個參數(shù):
- action:security登錄的url,可以自定義。
- username:security登錄的用戶名,可以自定義。
- password:security登錄的密碼,可以自定義。
以上三個參數(shù)都可以在security通過配置的方式定義。
3. 新建首頁
這個是登錄成功后跳轉(zhuǎn)的首頁,代碼如下:
4. 新建接口
在security中一切的接口都稱之為資源,下面新建兩個測試接口,代碼如下:
5. formLogin配置
在介紹如何配置之前,先來看下formLogin模式登錄的5個要素:
- 登錄認證邏輯-登錄URL:這個URL在security中默認是/login且POST請求,但是也可以通過配置自定義。
- 如何接收登錄參數(shù):用戶名、密碼默認接收的字段分別是username、password,同樣也是可以通過配置自定義。
- 登陸成功后邏輯:登錄成功后的處理邏輯,比如跳轉(zhuǎn)到指定的頁面、返回特定的JSON數(shù)據(jù),這個也是可以定制。
- 資源訪問控制規(guī)則:這個用于控制什么用戶、什么角色可以訪問什么資源,可以靜態(tài)指定也可以從數(shù)據(jù)庫中加載。
- 用戶具有角色權限:配置某個用戶擁有什么角色、擁有什么權限,可以靜態(tài)指定也可以從數(shù)據(jù)庫中加載。
一般來說,使用權限認證框架的的業(yè)務系統(tǒng)登錄驗證邏輯是固定的,而資源訪問控制規(guī)則和用戶信息是從數(shù)據(jù)庫或其他存儲介質(zhì)靈活加載的。但本文所有的用戶、資源、權限信息都是代碼配置寫死的,旨在為大家介紹formLogin認證模式,如何從數(shù)據(jù)庫加載權限認證相關信息我還會結合RBAC權限模型再寫文章的。
針對上述5個的要素,formLogin配置代碼如下:
首先,我們要繼承WebSecurityConfigurerAdapte?r ,重寫configure(HttpSecurity http) 方法,該方法用來配置登錄驗證邏輯。請注意看代碼中的注釋信息。
上述代碼分為兩個部分:
第一部分是formLogin配置段,用于配置登錄驗證邏輯相關的信息。如:登錄頁面、登錄成功頁面、登錄請求處理路徑等。
- .loginPage("/login/page")?:指定的第2步定制的登錄頁面,需要寫個mvc接口跳轉(zhuǎn)到login.html,見源碼。
- .loginProcessingUrl("/login")?:指定處理登錄的邏輯的url,這個接口不需要開發(fā)者定義,security中通過過濾器。UsernamePasswordAuthenticationFilter處理,后文介紹。
- .usernameParameter("username")?:指定用戶名的接收參數(shù)的字段,默認是username,具體邏輯在UsernamePasswordAuthenticationFilter。
- .passwordParameter("password")?:指定密碼的接收參數(shù)的字段,默認是username,具體邏輯在UsernamePasswordAuthenticationFilter。
- .defaultSuccessUrl("/")?:登錄認證成功后默認轉(zhuǎn)跳的路徑,這里/?則是跳轉(zhuǎn)到/index.html,可以自定義。
- .failureUrl("/login/page"):登陸失敗的跳轉(zhuǎn)的路徑。
第二部分是authorizeRequests配置段,用于配置資源的訪問控制規(guī)則
- .antMatchers("/login/page","/login").permitAll():配置登錄頁面、登錄接口直接放行,不需要攔截登錄
- .antMatchers("/","/hello1").hasAnyAuthority("ROLE_user","ROLE_admin")?:設置/hello1、/?這兩個資源需要user和admin的角色才可以訪問。
- .antMatchers("/hello2").hasAnyRole("admin")?:配置/hello2?這個資源需要admin的角色才可以訪問。
- .anyRequest().authenticated():除了上面的配置的規(guī)則,訪問其他的資源都需要登錄認證通過才可以訪問。
6. 用戶、角色配置
在上述的規(guī)則中配置了一些資源需要特定的角色才可以訪問,比如user、admin,那么這些角色如何去指定呢?
在security中提供了配置的方式,代碼如下:
上述的代碼配置很簡單,創(chuàng)建了兩個用戶且指定了角色,分別如下:
- user:密碼123456,賦予的角色為user。
- admin:密碼123456,賦予的角色為user、admin。
配置解釋如下:
- .inMemoryAuthentication():指的是在內(nèi)存里面存儲用戶的身份認證和授權信息;這里還可以配置從數(shù)據(jù)庫中動態(tài)加載,后文介紹。
- withUser("user"):用戶名是user。
- password(passwordEncoder().encode("123456")):密碼是加密之后的123456。
- roles():方法用于指定用戶的角色,一個用戶可以有多個角色。
- passwordEncoder(passwordEncoder())?:指定密碼的加密方式,使用的是BCryptPasswordEncoder,后文介紹。
7. 簡單測試
按照上述6個步驟基本實現(xiàn)了一個表單登錄,下面測試一下。
瀏覽器訪問http://localhost:8081/hello2,第一次訪問由于未登錄會自動跳轉(zhuǎn)到登錄頁面,如下圖:
輸入用戶名和密碼,由于/hello2?這個資源需要admin?的角色才能訪問,因此必須用admin這個用戶登錄,否則將會報403的錯誤,登錄成功后將能夠正常訪問。
如果用戶名或者密碼錯誤將會觸發(fā).failureUrl("/login/page")這個配置,自動跳轉(zhuǎn)到登錄頁面
8. 自定義登錄結果
在第5步的配置中,和登錄結果相關的配置有如下兩個:
- .defaultSuccessUrl("/")?:登錄認證成功后默認轉(zhuǎn)跳的路徑,這里/?則是跳轉(zhuǎn)到/index.html,可以自定義。
- .failureUrl("/login/page"):登陸失敗的跳轉(zhuǎn)的路徑。
這兩個配置都是指定URL的方式:
- 當我們登錄成功的時候,是由AuthenticationSuccessHandler?進行登錄結果處理,默認跳轉(zhuǎn)到defaultSuccessUrl配置的路徑對應的資源頁面(一般是首頁index.html)。
- 當我們登錄失敗的時候,是由AuthenticationfailureHandler?進行登錄結果處理,默認跳轉(zhuǎn)到failureUrl配置的路徑對應的資源頁面(一般也是跳轉(zhuǎn)登錄頁login.html,重新登錄)。
但是在web應用開發(fā)過程中需求是千變?nèi)f化的,有時需要我們針對登錄結果做個性化處理,比如:
- 我們希望不同的人登陸之后,看到不同的首頁(及向不同的路徑跳轉(zhuǎn))。
- 我們應用是前后端分離的,驗證響應結果是JSON格式數(shù)據(jù),而不是頁面跳轉(zhuǎn)。
- …… 其他未盡的例子。
因此需要自定義的登錄結果,這篇文章先介紹如何定制跳轉(zhuǎn)頁面,關于JSON格式數(shù)據(jù)就是前后端分離架構下需要用到。
8.1 自定義登錄成功結果
AuthenticationSuccessHandler?接口是Security提供的認證成功處理器接口,我們只需要去實現(xiàn)它即可。但是通常來說,我們不會直接去實現(xiàn)AuthenticationSuccessHandler?接口,而是繼承SavedRequestAwareAuthenticationSuccessHandler? 類,這個類會記住用戶上一次請求的資源路徑,比如/hello2?這個路徑,登錄成功后將會自動跳轉(zhuǎn)到/hello2這個頁面而不是首頁。
代碼如下:
8.2 自定義登錄失敗結果
這里我們同樣沒有直接實現(xiàn)AuthenticationFailureHandler?接口,而是繼承SimpleUrlAuthenticationFailureHandler 類。該類中默認實現(xiàn)了登錄驗證失敗的跳轉(zhuǎn)邏輯,即登陸失敗之后回到登錄頁面。我們可以利用這一點簡化我們的代碼。
代碼如下:
8.3 SecurityConfig中配置
配置如下:
將自定義的AuthenticationSuccessHandler和AuthenticationFailureHandler注入到Spring Security配置類中
使用formlogin模式,配置successHandler和failureHandler。
不要配置defaultSuccessUrl和failureUrl,否則自定義handler將失效。handler配置與URL配置只能二選一
總結
本篇文章介紹了Spring Security 的 formLogin的配置方式,需要注意的是這里不支持前后端分離架構,