Java中AuthorizationFilter過濾器的功能
AuthorizationFilter過濾器的作用
在 Spring Security 框架中,AuthorizationFilter 是負(fù)責(zé)執(zhí)行授權(quán)(Authorization) 決策的核心過濾器。根據(jù)當(dāng)前的 Authentication(認(rèn)證信息)和請(qǐng)求上下文,判斷當(dāng)前用戶是否有權(quán)限訪問目標(biāo)資源。
先看段源碼
public class AuthorizationFilter extends GenericFilterBean {
...
private final AuthorizationManager<HttpServletRequest> authorizationManager;
/**
* Creates an instance.
* @param authorizationManager the {@link AuthorizationManager} to use
*/
public AuthorizationFilter(AuthorizationManager<HttpServletRequest> authorizationManager) {
Assert.notNull(authorizationManager, "authorizationManager cannot be null");
this.authorizationManager = authorizationManager;
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
if (this.observeOncePerRequest && isApplied(request)) {
chain.doFilter(request, response);
return;
}
if (skipDispatch(request)) {
chain.doFilter(request, response);
return;
}
String alreadyFilteredAttributeName = getAlreadyFilteredAttributeName();
request.setAttribute(alreadyFilteredAttributeName, Boolean.TRUE);
try {
//授權(quán)決策
AuthorizationDecision decision = this.authorizationManager.check(this::getAuthentication, request);
this.eventPublisher.publishAuthorizationEvent(this::getAuthentication, request, decision);
if (decision != null && !decision.isGranted()) {
throw new AccessDeniedException("Access Denied");
}
chain.doFilter(request, response);
}
finally {
request.removeAttribute(alreadyFilteredAttributeName);
}
}
從上面的代碼中可以看出:AuthorizationFilter 本身不直接做授權(quán)判斷,而是委托給一個(gè) AuthorizationManager 接口.
AuthorizationManager
從上面的代碼中可以看出,授權(quán)的核心在于調(diào)用authorizationManager的check方法,去決定當(dāng)前的authentication是否有權(quán)限訪問request
//授權(quán)決策 AuthorizationDecision decision = this.authorizationManager.check(this::getAuthentication, request);
@FunctionalInterface
public interface AuthorizationManager<T> {
/**
* Determines if access should be granted for a specific authentication and object.
* @param authentication the {@link Supplier} of the {@link Authentication} to check
* @param object the {@link T} object to check
* @throws AccessDeniedException if access is not granted
*/
default void verify(Supplier<Authentication> authentication, T object) {
AuthorizationDecision decision = check(authentication, object);
if (decision != null && !decision.isGranted()) {
throw new AccessDeniedException("Access Denied");
}
}
/**
* Determines if access is granted for a specific authentication and object.
* @param authentication the {@link Supplier} of the {@link Authentication} to check
* @param object the {@link T} object to check
* @return an {@link AuthorizationDecision} or null if no decision could be made
*/
@Nullable
AuthorizationDecision check(Supplier<Authentication> authentication, T object);
}
AuthorizationManager接口定義了check方法,為什么說叫授權(quán)決策,因?yàn)閏heck方法返回的是AuthorizationDecision,這是一種授權(quán)結(jié)果 里面有個(gè)字段granted,用來決定是否有權(quán)限繼續(xù)訪問當(dāng)前資源。
public class AuthorizationDecision implements AuthorizationResult {
private final boolean granted;
public AuthorizationDecision(boolean granted) {
this.granted = granted;
}
@Override
public boolean isGranted() {
return this.granted;
}
@Override
public String toString() {
return getClass().getSimpleName() + " [granted=" + this.granted + "]";
}
}
RequestMatcherDelegatingAuthorizationManager
如果你去調(diào)試你會(huì)發(fā)現(xiàn)AuthorizationFilter委托的AuthorizationManager的實(shí)現(xiàn)類是 RequestMatcherDelegatingAuthorizationManager,至于為什么是這個(gè)實(shí)現(xiàn)類,我們后續(xù)會(huì)出一個(gè)文章專門來講解,大體還是HttpSecurity,因?yàn)樗褪怯脕砼渲眠^濾器鏈的,底層就是配置過濾器的。這里不會(huì)多講。拆解一下這個(gè)類的名字
- RequestMatcher:請(qǐng)求匹配器,用于匹配不同的 HTTP 請(qǐng)求(如 /admin/**, /public/**)
- Delegating:代表“委派”,即它自己不做判斷,而是把任務(wù)委派給其他具體的 AuthorizationManager
- AuthorizationManager:授權(quán)管理接口,負(fù)責(zé)做出“允許”或“拒絕”的決策
RequestMatcherDelegatingAuthorizationManager 內(nèi)部維護(hù)了一個(gè)列表mappings:
public final class RequestMatcherDelegatingAuthorizationManager implements AuthorizationManager<HttpServletRequest> {
private static final AuthorizationDecision DENY = new AuthorizationDecision(false);
private final List<RequestMatcherEntry<AuthorizationManager<RequestAuthorizationContext>>> mappings;
/**
* A rich object for associating a {@link RequestMatcher} to another object.
* 從注釋中可以看出RequestMatcherEntry就是用來將RequestMatcher和其他對(duì)象建立關(guān)聯(lián)的
* @author Marcus Da Coregio
* @since 5.5.5
*/
public class RequestMatcherEntry<T> {
private final RequestMatcher requestMatcher;
private final T entry;
public RequestMatcherEntry(RequestMatcher requestMatcher, T entry) {
this.requestMatcher = requestMatcher;
this.entry = entry;
}
public RequestMatcher getRequestMatcher() {
return this.requestMatcher;
}
public T getEntry() {
return this.entry;
}
}
mappings中的每個(gè)條目RequestMatcherEntry代表著一種映射關(guān)系,里面包含了
- 一個(gè) RequestMatcher(比如 AntPathRequestMatcher("/admin/**", "GET"))
- 一個(gè)對(duì)應(yīng)的 AuthorizationManager(比如負(fù)責(zé)判斷 hasRole('ADMIN') 的管理器)
接下來我們看下RequestMatcherDelegatingAuthorizationManager的check流程
/**
* Delegates to a specific {@link AuthorizationManager} based on a
* {@link RequestMatcher} evaluation.
* @param authentication the {@link Supplier} of the {@link Authentication} to check
* @param request the {@link HttpServletRequest} to check
* @return an {@link AuthorizationDecision}. If there is no {@link RequestMatcher}
* matching the request, or the {@link AuthorizationManager} could not decide, then
* null is returned
*/
@Override
public AuthorizationDecision check(Supplier<Authentication> authentication, HttpServletRequest request) {
if (this.logger.isTraceEnabled()) {
this.logger.trace(LogMessage.format("Authorizing %s", requestLine(request)));
}
for (RequestMatcherEntry<AuthorizationManager<RequestAuthorizationContext>> mapping : this.mappings) {
RequestMatcher matcher = mapping.getRequestMatcher();
MatchResult matchResult = matcher.matcher(request);
if (matchResult.isMatch()) {
AuthorizationManager<RequestAuthorizationContext> manager = mapping.getEntry();
if (this.logger.isTraceEnabled()) {
this.logger.trace(
LogMessage.format("Checking authorization on %s using %s", requestLine(request), manager));
}
return manager.check(authentication,
new RequestAuthorizationContext(request, matchResult.getVariables()));
}
}
if (this.logger.isTraceEnabled()) {
this.logger.trace(LogMessage.of(() -> "Denying request since did not find matching RequestMatcher"));
}
return DENY;
}
從上面的代碼我們可以看出check的核心流程是:當(dāng)請(qǐng)求到來時(shí),它會(huì):
- 遍歷這個(gè)列表,取出里面的每個(gè)RequestMatcher,然后去判斷當(dāng)前
RequestMatcher是否和當(dāng)前請(qǐng)求request匹配,找到匹配后,找到和RequestMatcher匹配的AuthorizationManager - 將授權(quán)任務(wù)委托給該條目對(duì)應(yīng)的
AuthorizationManager。 - 如果沒有任何匹配,默認(rèn)拒絕(或使用默認(rèn)策略)。
mappings列表中注冊(cè)的RequestMatcher和AuthorizationManager關(guān)系是如何綁定的
后續(xù)我會(huì)專門出一期文章從源碼角度講解RequestMatcherDelegatingAuthorizationManager是如何完成創(chuàng)建以及初始化mappings的,這里我們會(huì)如何使用就好啦。我們經(jīng)常在配置過濾器鏈的時(shí)候有如下配置
@Bean
public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http)
throws Exception {
System.out.println("filterChain http: " + System.identityHashCode(http));
http
.authorizeHttpRequests((authorize) -> authorize
.requestMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
);
return http.build();
}
比如這句代碼.requestMatchers("/admin/**").hasRole("ADMIN")就是在配置mappings映射關(guān)系,也就是當(dāng)訪問/admin/**時(shí),底層會(huì)創(chuàng)建一個(gè)AuthorityAuthorizationManager來處理授權(quán)決策(這塊后面出一篇文章細(xì)講),.hasRole("ADMIN")底層會(huì)創(chuàng)建一個(gè)AuthorizationManager來處理授權(quán)請(qǐng)求。
授權(quán)結(jié)果
從 AuthorizationFilter的源碼中我們知道,如果授權(quán)沒通過的話就會(huì)拋出一個(gè)AccessDeniedException異常,這個(gè)異常通常會(huì)被ExceptionTranslationFilter過濾器捕獲 然后進(jìn)行處理,這個(gè)我們后續(xù)再將
if (decision != null && !decision.isGranted()) { throw new AccessDeniedException("Access Denied"); }
總結(jié)
AuthorizationFilter過濾器是用來實(shí)現(xiàn)授權(quán)決策的,但是它會(huì)委托給 RequestMatcherDelegatingAuthorizationManager來實(shí)現(xiàn)具體的授權(quán)決策,結(jié)合當(dāng)前請(qǐng)求和authentication來決定是否有權(quán)限。但是這里我也留下了幾處坑,沒有填,后續(xù)我會(huì)寫文章繼續(xù)填坑
- AuthorizationFilter里面的RequestMatcherDelegatingAuthorizationManager是什么時(shí)候配置的
- RequestMatcherDelegatingAuthorizationManager需要維護(hù)一個(gè)mappings,用來映射requestMatcher和authorizationManager
- 用戶配置調(diào)用的
requestMatchers("/admin/**").hasRole("ADMIN")等配置,最后怎么生效的,底層原理是什么 4.授權(quán)沒通過拋出的異常被 ExceptionTranslationFilter捕獲后如何自定義處理。
到此這篇關(guān)于Java中AuthorizationFilter過濾器的功能的文章就介紹到這了,更多相關(guān)Java AuthorizationFilter過濾器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
springboot如何連接兩個(gè)數(shù)據(jù)庫(多個(gè))
這篇文章主要介紹了springboot如何連接兩個(gè)數(shù)據(jù)庫(多個(gè)),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01
Java基于遞歸和循環(huán)兩種方式實(shí)現(xiàn)未知維度集合的笛卡爾積算法示例
這篇文章主要介紹了Java基于遞歸和循環(huán)兩種方式實(shí)現(xiàn)未知維度集合的笛卡爾積算法,結(jié)合實(shí)例形式分析了Java使用遞歸與循環(huán)兩種方式實(shí)現(xiàn)未知維度集合的笛卡爾積相關(guān)概念、原理與操作技巧,需要的朋友可以參考下2017-12-12
Java Lambda和Stream開發(fā)中20個(gè)高頻錯(cuò)誤案例分析與避坑指南
本篇文章將聚焦開發(fā)中最常見、最高頻的20個(gè)問題(含語法、函數(shù)式接口、Stream流、方法引用、并行流5大模塊),每個(gè)問題都配套問題描述+錯(cuò)誤案例+原因分析+正確解法,希望對(duì)大家有所幫助2026-04-04
實(shí)戰(zhàn)分布式醫(yī)療掛號(hào)系統(tǒng)之整合Swagger2到通用模塊
這篇文章主要為大家介紹了實(shí)戰(zhàn)分布式醫(yī)療掛號(hào)系統(tǒng)之整合Swagger2到通用模塊,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-04-04
使用SpringBoot集成Redis實(shí)現(xiàn)CRUD功能
本文主要介紹了使用SpringBoot集成Redis實(shí)現(xiàn)CRUD功能,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2025-10-10

