1. 程式人生 > >Spring Security Web 5.1.2 原始碼解析 -- AnonymousAuthenticationFilter

Spring Security Web 5.1.2 原始碼解析 -- AnonymousAuthenticationFilter

概述

此過濾器過濾請求,檢測SecurityContextHolder中是否存在Authentication物件,如果不存在,說明使用者尚未登入,此時為其提供一個匿名Authentication物件:AnonymousAuthentication

注意:在整個請求處理的開始,無論當前請求所對應的session中使用者是否已經登入,SecurityContextPersistenceFilter
都會確保SecurityContextHolder中保持一個SecurityContext物件。但如果使用者尚未登入,這個的SecurityContext
象會是一個空物件,也就是其屬性Authentication

null。然後在該請求處理過程中,如果一直到當前Filter
行,SecurityContextHolderSecurityContext物件屬性Authentication仍是null,該AnonymousAuthenticationFilter就將其
修改為一個AnonymousAuthentication物件,表明這是一個匿名訪問。

原始碼解析

package org.springframework.security.web.authentication;

import java.io.IOException;
import java.util.*;

import
javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import org.springframework.beans.factory.InitializingBean; import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.authentication.AuthenticationDetailsSource; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.util.Assert; import org.springframework.web.filter.GenericFilterBean; /** * Detects if there is no Authentication object in the * SecurityContextHolder, and populates it with one if needed. * * 檢測 SecurityContextHolder中是否存在Authentication物件,如果不存在,說明 * 使用者尚未登入,此時為其提供一個匿名 Authentication: AnonymousAuthentication物件。 * * @author Ben Alex * @author Luke Taylor */ public class AnonymousAuthenticationFilter extends GenericFilterBean implements InitializingBean { // ~ Instance fields // ================================================================================================ // 用於構造匿名Authentication中詳情屬性的詳情來源物件,這裡使用一個WebAuthenticationDetailsSource private AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource = new WebAuthenticationDetailsSource(); private String key; private Object principal; private List<GrantedAuthority> authorities; /** * Creates a filter with a principal named "anonymousUser" and the single authority * "ROLE_ANONYMOUS". * 使用外部指定的key構造一個AnonymousAuthenticationFilter: * 1. 預設情況下,Spring Security 配置機制為這裡指定的key是一個隨機的uuid; * 2. 所對應的 princpial(含義指當前登入主體) 是一個字串"anonymousUser"; * 3. 所擁護的角色是 "ROLE_ANONYMOUS"; * @param key the key to identify tokens created by this filter */ public AnonymousAuthenticationFilter(String key) { this(key, "anonymousUser", AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS")); } /** * 使用外部指定的引數構造一個AnonymousAuthenticationFilter * @param key key the key to identify tokens created by this filter * @param principal the principal which will be used to represent anonymous users * @param authorities the authority list for anonymous users */ public AnonymousAuthenticationFilter(String key, Object principal, List<GrantedAuthority> authorities) { Assert.hasLength(key, "key cannot be null or empty"); Assert.notNull(principal, "Anonymous authentication principal must be set"); Assert.notNull(authorities, "Anonymous authorities must be set"); this.key = key; this.principal = principal; this.authorities = authorities; } // ~ Methods // ======================================================================================================== @Override public void afterPropertiesSet() { // 在當前Filter bean被建立時呼叫,主要目的是斷言三個主要屬性都必須已經有效設定 Assert.hasLength(key, "key must have length"); Assert.notNull(principal, "Anonymous authentication principal must be set"); Assert.notNull(authorities, "Anonymous authorities must be set"); } public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { if (SecurityContextHolder.getContext().getAuthentication() == null) { // 如果SecurityContextHolder中SecurityContext物件的屬性authentication是null, // 將其替換成一個匿名 Authentication: AnonymousAuthentication SecurityContextHolder.getContext().setAuthentication( createAuthentication((HttpServletRequest) req)); if (logger.isDebugEnabled()) { logger.debug("Populated SecurityContextHolder with anonymous token: '" + SecurityContextHolder.getContext().getAuthentication() + "'"); } } else { if (logger.isDebugEnabled()) { logger.debug("SecurityContextHolder not populated with anonymous token, as it already contained: '" + SecurityContextHolder.getContext().getAuthentication() + "'"); } } // 對SecurityContextHolder中SecurityContext物件的屬性authentication做過以上處理之後,繼續 // filter chain 的執行 chain.doFilter(req, res); } // 根據指定屬性key,princpial,authorities和當前環境(servlet web環境)構造一個AnonymousAuthenticationToken protected Authentication createAuthentication(HttpServletRequest request) { AnonymousAuthenticationToken auth = new AnonymousAuthenticationToken(key, principal, authorities); auth.setDetails(authenticationDetailsSource.buildDetails(request)); return auth; } // 可以外部指定Authentication物件的詳情來源, 預設情況下使用的是WebAuthenticationDetailsSource, // 已經在屬性authenticationDetailsSource初始化指定 public void setAuthenticationDetailsSource( AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource) { Assert.notNull(authenticationDetailsSource, "AuthenticationDetailsSource required"); this.authenticationDetailsSource = authenticationDetailsSource; } public Object getPrincipal() { return principal; } public List<GrantedAuthority> getAuthorities() { return authorities; } }

其他文章

Spring Security Web 5.1.2 原始碼解析 – 安全相關Filter清單