【深入】聊聊權(quán)限
常見(jiàn)的權(quán)限模型
ACL
定義:規(guī)定資源可以被哪些主體進(jìn)行哪些操作。同時(shí),主體可以將資源、操作的權(quán)限,授予其他主體。
在ACL的基礎(chǔ)上,DAC模型將授權(quán)的權(quán)力下放,允許擁有權(quán)限的用戶,可以自主地將權(quán)限授予其他用戶。

DAC 自主訪問(wèn)控制
定義:規(guī)定資源可以被哪些主體進(jìn)行哪些操作。同時(shí),主體可以將資源、操作的權(quán)限,授予其他主體。
在ACL的基礎(chǔ)上,DAC模型將授權(quán)的權(quán)力下放,允許擁有權(quán)限的用戶,可以自主地將權(quán)限授予其他用戶。
MAC 強(qiáng)制訪問(wèn)控制
定義:當(dāng)一個(gè)操作,同時(shí)滿足a與b時(shí),允許操作
a. 規(guī)定資源可以被哪些類(lèi)別的主體進(jìn)行哪些操作
b. 規(guī)定主體可以對(duì)哪些等級(jí)的資源進(jìn)行哪些操作
MAC是ACL的另一種實(shí)現(xiàn),強(qiáng)調(diào)安全性。MAC會(huì)在系統(tǒng)中,對(duì)資源與主體,都劃分類(lèi)別與等級(jí)。比如,等級(jí)分為:秘密級(jí)、機(jī)密級(jí)、絕密級(jí);類(lèi)別分為:軍事人員、財(cái)務(wù)人員、行政人員。
MAC的優(yōu)勢(shì)就是實(shí)現(xiàn)資源與主體的雙重驗(yàn)證,確保資源的交叉隔離,提高安全性。
RBAC 基于角色的訪問(wèn)控制
定義:當(dāng)一個(gè)操作,同時(shí)滿足a與b時(shí),允許操作。
a. 規(guī)定角色可以對(duì)哪些資源進(jìn)行哪些操作
b. 規(guī)定主體擁有哪些角色
RBAC的思想,來(lái)源于現(xiàn)實(shí)世界的企業(yè)結(jié)構(gòu)。比如,銷(xiāo)售角色,擁有查看客戶信息的權(quán)限。當(dāng)一個(gè)銷(xiāo)售人員小王入職了,可以把銷(xiāo)售角色賦予小王,那么小王就擁有了查看客戶的權(quán)限。這種方式,避免了ACL模型下,每次新人入職,需要逐個(gè)配置資源表的情況。同樣,權(quán)限變動(dòng)也變得很方便,只要修改角色,即可實(shí)現(xiàn)多用戶的權(quán)限修改。
ABAC 基于屬性的訪問(wèn)控制
定義:規(guī)定哪些屬性的主體可以對(duì)哪些屬性的資源在哪些屬性的情況下進(jìn)行哪些操作
ABAC其中的屬性就是與主體、資源、情況相關(guān)的所有信息。
主體的屬性:指的是與主體相關(guān)的所有信息,包括主體的年齡、性別、職位等。
資源的屬性:指的是與資源相關(guān)的所有信息,包括資源的創(chuàng)建時(shí)間、創(chuàng)建位置、密級(jí)等。
情況的屬性:指的是客觀情況的屬性,比如當(dāng)前的時(shí)間、當(dāng)前的位置、當(dāng)前的場(chǎng)景(普通狀態(tài)、緊急狀態(tài))。
操作:含義還是一樣,比如增刪改查等。
設(shè)定一個(gè)權(quán)限,就是定義一條含有四類(lèi)屬性信息的策略(Policy)。
**一個(gè)請(qǐng)求會(huì)逐條匹配策略,如果沒(méi)有匹配到策略,則返回默認(rèn)效果,默認(rèn)效果可以根據(jù)場(chǎng)景定制,可以是默認(rèn)拒絕或是默認(rèn)允許。**另外,匹配方式也可以根據(jù)場(chǎng)景定制,可以使用逐條順序匹配,匹配到策略直接返回。也可以使用完全匹配,匹配所有的策略,如果有一個(gè)拒絕(允許),則拒絕(允許)。
Linux權(quán)限D(zhuǎn)AC 安全模型
DAC 的核心內(nèi)容是:在 Linux 中,進(jìn)程理論上所擁有的權(quán)限與執(zhí)行它的用戶的權(quán)限相同。其中涉及的一切內(nèi)容,都是圍繞這個(gè)核心進(jìn)行的。
用戶和組 ID 信息控制
用戶、組、口令信息
通過(guò) /etc/passwd 和 /etc/group 保存用戶和組信息,通過(guò) /etc/shadow 保存密碼口令及其變動(dòng)信息, 每行一條記錄。
用戶和組分別用 UID 和 GID 表示,一個(gè)用戶可以同時(shí)屬于多個(gè)組,默認(rèn)每個(gè)用戶必屬于一個(gè)與之 UID 同值同名的 GID 。
對(duì)于 /etc/passwd , 每條記錄字段分別為 用戶名: 口令(在 /etc/shadow 加密保存):UID:GID(默認(rèn) UID): 描述注釋: 主目錄: 登錄 shell(第一個(gè)運(yùn)行的程序)
對(duì)于 /etc/group , 每條記錄字段分別為 組名:口令(一般不存在組口令):GID:組成員用戶列表(逗號(hào)分割的用戶 UID 列表)
對(duì)于 /etc/shadow ,每條記錄字段分別為:登錄名: 加密口令: 最后一次修改時(shí)間: 最小時(shí)間間隔: 最大時(shí)間間隔: 警告時(shí)間: 不活動(dòng)時(shí)間:
舉例
以下是對(duì)用戶和組信息的舉例。/etc/shadow 中的口令信息為加密存儲(chǔ),不舉例。
文件權(quán)限控制信息
文件類(lèi)型
Linux 中的文件有如下類(lèi)型:
普通文件, 又包括文本文件和二進(jìn)制文件, 可用 touch 創(chuàng)建;
套接字文件, 用于網(wǎng)絡(luò)通訊,一般由應(yīng)用程序在執(zhí)行中間接創(chuàng)建;
管道文件是有名管道,而非無(wú)名管道, 可用 mkfifo 創(chuàng)建;
字符文件和塊文件均為設(shè)備文件, 可用 mknod 創(chuàng)建;
鏈接文件是軟鏈接文件,而非硬鏈接文件, 可用 ln 創(chuàng)建。
訪問(wèn)權(quán)限控制組
分為三組進(jìn)行控制:
user 包含對(duì)文件屬主設(shè)定的權(quán)限
group 包含對(duì)文件屬組設(shè)定的權(quán)限
others 包含對(duì)其他者設(shè)定的權(quán)限
可設(shè)定的權(quán)限
下面給出常見(jiàn)(但非全部)的權(quán)限值, 包括:
r 表示具有讀權(quán)限。
w 表示具有寫(xiě)權(quán)限。
x 一般針對(duì)可執(zhí)行文件 / 目錄,表示具有執(zhí)行 / 搜索權(quán)限。
s 一般針對(duì)可執(zhí)行文件 / 目錄,表示具有賦予文件屬主權(quán)限的權(quán)限,只有 user 和 group 組可以設(shè)置該權(quán)限。
t 一般針對(duì)目錄,設(shè)置粘滯位后,有權(quán)限的用戶只能寫(xiě)、刪除自己的文件, 否則可寫(xiě)、刪除目錄所有文件。舊系統(tǒng)還表示可執(zhí)行文件運(yùn)行后將 text 拷貝到交換區(qū)提升速度。
舉例
通過(guò) ls -l 可以查看到其文件類(lèi)型及權(quán)限,通過(guò) chmod 修改權(quán)限。
舉例來(lái)說(shuō),
RBAC權(quán)限模型簡(jiǎn)介
RBAC權(quán)限模型(Role-Based Access Control)即:基于角色的權(quán)限控制。模型中有幾個(gè)關(guān)鍵的術(shù)語(yǔ):
用戶:系統(tǒng)接口及訪問(wèn)的操作者
權(quán)限:能夠訪問(wèn)某接口或者做某操作的授權(quán)資格
角色:具有一類(lèi)相同操作權(quán)限的用戶的總稱
RBAC權(quán)限模型核心授權(quán)邏輯如下:
某用戶是什么角色?
某角色具有什么權(quán)限?
通過(guò)角色的權(quán)限推導(dǎo)用戶的權(quán)限
RBAC的演化進(jìn)程
用戶與權(quán)限直接關(guān)聯(lián)

想到權(quán)限控制,人們最先想到的一定是用戶與權(quán)限直接關(guān)聯(lián)的模式,簡(jiǎn)單地說(shuō)就是:某個(gè)用戶具有某些權(quán)限。如圖:
張三具有創(chuàng)建用戶和刪除用戶的權(quán)限,所以他可能系統(tǒng)維護(hù)人員
李四具有產(chǎn)品記錄管理和銷(xiāo)售記錄管理權(quán)限,所以他可能是一個(gè)業(yè)務(wù)銷(xiāo)售人員
這種模型能夠清晰的表達(dá)用戶與權(quán)限之間的關(guān)系,足夠簡(jiǎn)單。但同時(shí)也存在問(wèn)題:
現(xiàn)在用戶是張三、李四,以后隨著人員增加,每一個(gè)用戶都需要重新授權(quán)
或者張三、李四離職,需要針對(duì)每一個(gè)用戶進(jìn)行多種權(quán)限的回收
一個(gè)用戶擁有一個(gè)角色
在實(shí)際的團(tuán)體業(yè)務(wù)中,都可以將用戶分類(lèi)。比如對(duì)于薪水管理系統(tǒng),通常按照級(jí)別分類(lèi):經(jīng)理、高級(jí)工程師、中級(jí)工程師、初級(jí)工程師。也就是按照一定的角色分類(lèi),通常具有同一角色的用戶具有相同的權(quán)限。這樣改變之后,就可以將針對(duì)用戶賦權(quán)轉(zhuǎn)換為針對(duì)角色賦權(quán)。

一個(gè)用戶有一個(gè)角色
一個(gè)角色有多個(gè)操作(菜單)權(quán)限
一個(gè)操作權(quán)限可以屬于多個(gè)角色
我們可以用下圖中的數(shù)據(jù)庫(kù)設(shè)計(jì)模型,描述這樣的關(guān)系。

一個(gè)用戶一個(gè)或多個(gè)角色
但是在實(shí)際的應(yīng)用系統(tǒng)中,一個(gè)用戶一個(gè)角色遠(yuǎn)遠(yuǎn)滿足不了需求。如果我們希望一個(gè)用戶既擔(dān)任銷(xiāo)售角色、又暫時(shí)擔(dān)任副總角色。該怎么做呢?為了增加系統(tǒng)設(shè)計(jì)的適用性,我們通常設(shè)計(jì):
一個(gè)用戶有一個(gè)或多個(gè)角色
一個(gè)角色包含多個(gè)用戶
一個(gè)角色有多種權(quán)限
一個(gè)權(quán)限屬于多個(gè)角色
我們可以用下圖中的數(shù)據(jù)庫(kù)設(shè)計(jì)模型,描述這樣的關(guān)系。

頁(yè)面訪問(wèn)權(quán)限與操作權(quán)限
頁(yè)面訪問(wèn)權(quán)限: 所有系統(tǒng)都是由一個(gè)個(gè)的頁(yè)面組成,頁(yè)面再組成模塊,用戶是否能看到這個(gè)頁(yè)面的菜單、是否能進(jìn)入這個(gè)頁(yè)面就稱為頁(yè)面訪問(wèn)權(quán)限。
操作權(quán)限: 用戶在操作系統(tǒng)中的任何動(dòng)作、交互都需要有操作權(quán)限,如增刪改查等。比如:某個(gè)按鈕,某個(gè)超鏈接用戶是否可以點(diǎn)擊,是否應(yīng)該看見(jiàn)的權(quán)限。

為了適應(yīng)這種需求,我們可以把頁(yè)面資源(菜單)和操作資源(按鈕)分表存放,如上圖。也可以把二者放到一個(gè)表里面存放,用一個(gè)字段進(jìn)行標(biāo)志區(qū)分。
數(shù)據(jù)權(quán)限
數(shù)據(jù)權(quán)限比較好理解,就是某個(gè)用戶能夠訪問(wèn)和操作哪些數(shù)據(jù)。
通常來(lái)說(shuō),數(shù)據(jù)權(quán)限由用戶所屬的組織來(lái)確定。比如:生產(chǎn)一部只能看自己部門(mén)的生產(chǎn)數(shù)據(jù),生產(chǎn)二部只能看自己部門(mén)的生產(chǎn)數(shù)據(jù);銷(xiāo)售部門(mén)只能看銷(xiāo)售數(shù)據(jù),不能看財(cái)務(wù)部門(mén)的數(shù)據(jù)。而公司的總經(jīng)理可以看所有的數(shù)據(jù)。
在實(shí)際的業(yè)務(wù)系統(tǒng)中,數(shù)據(jù)權(quán)限往往更加復(fù)雜。非常有可能銷(xiāo)售部門(mén)可以看生產(chǎn)部門(mén)的數(shù)據(jù),以確定銷(xiāo)售策略、安排計(jì)劃等。
所以為了面對(duì)復(fù)雜的需求,數(shù)據(jù)權(quán)限的控制通常是由程序員書(shū)寫(xiě)個(gè)性化的SQL來(lái)限制數(shù)據(jù)范圍的,而不是交給權(quán)限模型或者Spring Security或shiro來(lái)控制。當(dāng)然也可以從權(quán)限模型或者權(quán)限框架的角度去解決這個(gè)問(wèn)題,但適用性有限。
Spring Security
springsecurity底層實(shí)現(xiàn)為一條過(guò)濾器鏈,就是用戶請(qǐng)求進(jìn)來(lái),判斷有沒(méi)有請(qǐng)求的權(quán)限,拋出異常,重定向跳轉(zhuǎn)。
springsecurity自帶一個(gè)登錄頁(yè)。
從登陸入手,登錄頁(yè)替換成我們自己的,對(duì)輸入的賬號(hào)密碼進(jìn)行驗(yàn)證。
/*** 表單登陸security* 安全 = 認(rèn)證 + 授權(quán)*/public class SecurityConfig extends WebSecurityConfigurerAdapter {protected void configure(HttpSecurity http) throws Exception {//以下五步是表單登錄進(jìn)行身份認(rèn)證最簡(jiǎn)單的登陸環(huán)境http.formLogin() //表單登陸 1.and() //2.authorizeRequests() //下面的都是授權(quán)的配置 3.anyRequest() //任何請(qǐng)求 4.authenticated(); //訪問(wèn)任何資源都需要身份認(rèn)證 5}}

如果只實(shí)現(xiàn)一個(gè)WebSecurityConfigurerAdapter然后重寫(xiě)一下configure方法,效果會(huì)默認(rèn)使用springsecurity的登錄頁(yè) ,以及項(xiàng)目啟動(dòng)時(shí)后臺(tái)會(huì)打印出一個(gè)默認(rèn)的密碼,然后使用任意賬號(hào)就可以進(jìn)行登錄訪問(wèn)指定的資源
如果想要使用自己的登錄頁(yè) 并且用戶名密碼是自己數(shù)據(jù)庫(kù)中的,進(jìn)一步完善spring security認(rèn)證體系,首先需要做以下配置。
protected void configure(HttpSecurity http) throws Exception {//以下五步是表單登錄進(jìn)行身份認(rèn)證最簡(jiǎn)單的登陸環(huán)境http.formLogin() //表單登陸 1.loginPage("/login.html") //指定登陸頁(yè)面.and() //2.authorizeRequests() //下面的都是授權(quán)的配置 3.antMatchers("/login.html").permitAll()//訪問(wèn)此地址就不需要進(jìn)行身份認(rèn)證了,防止重定向死循環(huán).anyRequest() //任何請(qǐng)求 4.authenticated(); //訪問(wèn)任何資源都需要身份認(rèn)證 5}
然后實(shí)現(xiàn)UserDetailsService接口進(jìn)行用戶姓名密碼校驗(yàn) (由于springboot2.x中security是5.x版本的,所以這里的密碼是默認(rèn)做了BCrypt加密的,就需要bean一個(gè)BCrypt)
public class MyUserDetailService implements UserDetailsService {//注入mapper//...private PasswordEncoder passwordEncoder;private Logger LOG = LoggerFactory.getLogger(MyUserDetailService.class);public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {LOG.error("登陸用戶輸入的用戶名:{}",s);//根據(jù)用戶名查找用戶信息//密碼進(jìn)行bcrypt加密String pwd = "wangkai";//String cryptPwd = BCrypt.hashpw(pwd, BCrypt.gensalt());String cryptPwd = passwordEncoder.encode(pwd);LOG.error("加密后的密碼為: {}",cryptPwd);return new User("s",cryptPwd, AuthorityUtils.commaSeparatedStringToAuthorityList("admin")); //賬號(hào) 密碼 權(quán)限}}
/*** 表單登陸security* 安全 = 認(rèn)證 + 授權(quán)*/public class SecurityConfig extends WebSecurityConfigurerAdapter {/*** 介紹* springboot2.x引入的security版本是5.x的,這個(gè)版本需要提供一個(gè)PasswordEncoder實(shí)例,不然就會(huì)報(bào)錯(cuò)* @return*/public PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}protected void configure(HttpSecurity http) throws Exception {//以下五步是表單登錄進(jìn)行身份認(rèn)證最簡(jiǎn)單的登陸環(huán)境http.formLogin() //表單登陸 1.loginPage("/login.html") //指定登陸頁(yè)面.and() //2.authorizeRequests() //下面的都是授權(quán)的配置 3.antMatchers("/login.html").permitAll()//訪問(wèn)此地址就不需要進(jìn)行身份認(rèn)證了,防止重定向死循環(huán).anyRequest() //任何請(qǐng)求 4.authenticated(); //訪問(wèn)任何資源都需要身份認(rèn)證 5}}
添加登陸頁(yè)面提交頁(yè)面,關(guān)閉跨站請(qǐng)求偽造攻擊,登陸訪問(wèn)資源
<html lang="en"><head><meta charset="UTF-8"><title>登陸</title></head><body><h2>標(biāo)準(zhǔn)登陸頁(yè)面</h2><h3>表單登陸</h3><form action = "/authentication/form" method ="post"><table><tr><td>用戶名:</td><td><input type="text" name="username"></td></tr><tr><td>密碼:</td><td><input type="password" name="password"></td></tr><tr><td colspan="2"><button type="submit">登陸</button></td></tr></table></form></body></html>
@Overrideprotected void configure(HttpSecurity http) throws Exception {//以下五步是表單登錄進(jìn)行身份認(rèn)證最簡(jiǎn)單的登陸環(huán)境http.formLogin() //表單登陸 1.loginPage("/login.html") //指定登陸頁(yè)面.loginProcessingUrl("/authentication/form")//登陸頁(yè)面提交的頁(yè)面 開(kāi)始使用UsernamePasswordAuthenticationFilter過(guò)濾器處理請(qǐng)求.and() //2.authorizeRequests() //下面的都是授權(quán)的配置 3.antMatchers("/login.html").permitAll()//訪問(wèn)此地址就不需要進(jìn)行身份認(rèn)證了,防止重定向死循環(huán).anyRequest() //任何請(qǐng)求 4.authenticated() //訪問(wèn)任何資源都需要身份認(rèn)證 5.and().csrf().disable();//關(guān)閉跨站請(qǐng)求偽造攻擊攔截}
動(dòng)態(tài)配置登錄頁(yè)

.做一個(gè)我們自己默認(rèn)的登錄頁(yè),如果不想用默認(rèn)的也可以動(dòng)態(tài)配置。使用到的注解@ConfigurationProperties。
.增加接口/authentication/require
.引導(dǎo)用戶進(jìn)入登錄頁(yè)登陸
@Overrideprotected void configure(HttpSecurity http) throws Exception {//以下五步是表單登錄進(jìn)行身份認(rèn)證最簡(jiǎn)單的登陸環(huán)境http.formLogin() //表單登陸 1//.loginPage("/login.html") //指定登陸頁(yè)面.loginPage("/authentication/require").loginProcessingUrl("/authentication/form")//登陸頁(yè)面提交的頁(yè)面 開(kāi)始使用UsernamePasswordAuthenticationFilter過(guò)濾器處理請(qǐng)求.and() //2.authorizeRequests() //下面的都是授權(quán)的配置 3.antMatchers("/login.html","/authentication/require",securityProperties.getBrowser().getLoginPage()).permitAll()//訪問(wèn)此地址就不需要進(jìn)行身份認(rèn)證了,防止重定向死循環(huán).anyRequest() //任何請(qǐng)求 4.authenticated() //訪問(wèn)任何資源都需要身份認(rèn)證 5.and().csrf().disable();//關(guān)閉跨站請(qǐng)求偽造攻擊攔截}
public class BrowserSecurityController {private Logger LOG = LoggerFactory.getLogger(BrowserSecurityController.class);//將當(dāng)前請(qǐng)求緩存到session里private RequestCache requestCache = new HttpSessionRequestCache();private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();private SecurityProperties securityProperties;/*** 當(dāng)需要身份認(rèn)證時(shí)跳轉(zhuǎn)到這里* @param request* @param response* @return*/(value = "/authentication/require",method = RequestMethod.GET)(code = HttpStatus.UNAUTHORIZED) //未授權(quán)狀態(tài)碼public SimpleResponse requireAuthentication(HttpServletRequest request, HttpServletResponse response) throws IOException {//拿到引發(fā)跳轉(zhuǎn)的請(qǐng)求SavedRequest savedRequest = requestCache.getRequest(request,response);if(savedRequest != null){String targetUrl = savedRequest.getRedirectUrl();String fileUrl=new URL(targetUrl).getFile();LOG.info("引發(fā)跳轉(zhuǎn)的請(qǐng)求是:{}",targetUrl);if(StringUtils.endsWithIgnoreCase(targetUrl,".html") || fileUrl.equals("/")){//調(diào)轉(zhuǎn)到登錄頁(yè) 》》這里登錄頁(yè)做成可配置的redirectStrategy.sendRedirect(request,response,securityProperties.getBrowser().getLoginPage());}}return new SimpleResponse("訪問(wèn)資源需要登陸,請(qǐng)?jiān)L問(wèn)登陸頁(yè)面");}}
從配置文件中讀取當(dāng)訪問(wèn)資源需要身份認(rèn)證調(diào)轉(zhuǎn)的頁(yè)面地址
server.port=8888 #自定義springsecurity 登錄頁(yè)面 security.browser.loginPage = /mylogin.html
package com.example.security.properties;import com.example.security.pojo.SecurityBrowserPojo;import org.springframework.boot.context.properties.ConfigurationProperties;/*** 實(shí)現(xiàn)動(dòng)態(tài)配置用戶專(zhuān)屬登陸頁(yè)面*/(prefix = "security")public class SecurityProperties {private SecurityBrowserPojo browser = new SecurityBrowserPojo();public SecurityBrowserPojo getBrowser() {return browser;}public void setBrowser(SecurityBrowserPojo browser) {this.browser = browser;}}
public class SecurityBrowserPojo {//設(shè)置默認(rèn)地址private String loginPage = "/login.html";public String getLoginPage() {return loginPage;}public void setLoginPage(String loginPage) {this.loginPage = loginPage;}}
package com.example.security.config.securityconfig;import com.example.security.properties.SecurityProperties;import org.springframework.boot.context.properties.EnableConfigurationProperties;import org.springframework.context.annotation.Configuration;//設(shè)置注解讀取生效 (試了下不用配置這里@ConfigurationProperties也可以生效)public class SecurityPropertiesConfig {}
某些時(shí)候用戶登陸成功,登陸失敗的時(shí)候可能還需要做一些操作,比如成功登陸增加一積分之類(lèi)的操作,這里需要做兩個(gè)handler處理器
/*** 設(shè)置通過(guò)請(qǐng)求攔截。登陸成功后處理*/("wawAuthenticationSuccessHandler")public class WawAuthenticationSuccessHandler implements AuthenticationSuccessHandler {private Logger LOG = LoggerFactory.getLogger(WawAuthenticationSuccessHandler.class);private ObjectMapper objectMapper;/*** @param authentication 封裝認(rèn)證信息>>用戶信息 請(qǐng)求ip之類(lèi)的* @throws IOException* @throws ServletException*/public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {LOG.info("登陸成功");response.setContentType("application/json;charset=UTF-8");response.getWriter().write(objectMapper.writeValueAsString(authentication));}}
/*** 設(shè)置通過(guò)請(qǐng)求攔截。登陸失敗后處理*/("wawAuthenticationFailHandler")public class WawAuthenticationFailHandler implements AuthenticationFailureHandler{private Logger LOG = LoggerFactory.getLogger(WawAuthenticationFailHandler.class);private ObjectMapper objectMapper;public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {LOG.info("登陸失敗");response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());response.setContentType("application/json;charset=UTF-8");response.getWriter().write(objectMapper.writeValueAsString(e));}}
成功與失敗的處理器 配置到配置信息中
@Overrideprotected void configure(HttpSecurity http) throws Exception {//以下五步是表單登錄進(jìn)行身份認(rèn)證最簡(jiǎn)單的登陸環(huán)境http.formLogin() //表單登陸 1//.loginPage("/login.html") //指定登陸頁(yè)面.loginPage("/authentication/require").loginProcessingUrl("/authentication/form")//登陸頁(yè)面提交的頁(yè)面 開(kāi)始使用UsernamePasswordAuthenticationFilter過(guò)濾器處理請(qǐng)求.successHandler(wawAuthenticationSuccessHandler).failureHandler(wawAuthenticationFailHandler).and() //2.authorizeRequests() //下面的都是授權(quán)的配置 3.antMatchers("/authentication/require","/login.html",securityProperties.getBrowser().getLoginPage()).permitAll()//訪問(wèn)此地址就不需要進(jìn)行身份認(rèn)證了,防止重定向死循環(huán).anyRequest() //任何請(qǐng)求 4.authenticated() //訪問(wèn)任何資源都需要身份認(rèn)證 5.and().csrf().disable();//關(guān)閉跨站請(qǐng)求偽造攻擊攔截}
登陸失敗就會(huì)返回500 登陸異常信息

