欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java中的@PreAuthorize注解源碼解析

 更新時間:2023年10月07日 08:39:34   作者:Sterne_  
這篇文章主要介紹了Java中的@PreAuthorize注解源碼解析,@PreAuthorize注解會在方法執(zhí)行前進行權(quán)限驗證,支持Spring?EL表達式,它是基于方法注解的權(quán)限解決方案,需要的朋友可以參考下

一、PrePostAdviceReactiveMethodInterceptor類

作用

攔截@PreAuthorize注解標記的方法。

源碼分析

// 源碼存在刪減
public class PrePostAdviceReactiveMethodInterceptor implements MethodInterceptor {
	private Authentication anonymous = new AnonymousAuthenticationToken("key", "anonymous",
	private final MethodSecurityMetadataSource attributeSource;
	private final PreInvocationAuthorizationAdvice preInvocationAdvice;
	private final PostInvocationAuthorizationAdvice postAdvice;
	public PrePostAdviceReactiveMethodInterceptor(MethodSecurityMetadataSource attributeSource,
			PreInvocationAuthorizationAdvice preInvocationAdvice,
			PostInvocationAuthorizationAdvice postInvocationAdvice) {
		// attributeSource->PrePostAnnotationSecurityMetadataSource類,下文有相關(guān)解析
		this.attributeSource = attributeSource;
		// preInvocationAdvice->ExpressionBasedPreInvocationAdvice類,下文有相關(guān)解析
		this.preInvocationAdvice = preInvocationAdvice;
		this.postAdvice = postInvocationAdvice;
	}
    @Override
	public Object invoke(final MethodInvocation invocation) {
		Method method = invocation.getMethod();
		Class<?> returnType = method.getReturnType();
		Class<?> targetClass = invocation.getThis().getClass();
		// 關(guān)鍵步驟1,獲取當前方法的安全屬性集合,該方法解析在目錄標題二
		Collection<ConfigAttribute> attributes = this.attributeSource.getAttributes(method, targetClass);
		// 關(guān)鍵步驟2:獲取@PreAuthorize注解的value值
		PreInvocationAttribute preAttr = findPreInvocationAttribute(attributes);
		Mono<Authentication> toInvoke = ReactiveSecurityContextHolder.getContext() // Mono<SecurityContext>
				.map(SecurityContext::getAuthentication)// Mono<Authentication>
				.defaultIfEmpty(this.anonymous)
				// 關(guān)鍵步驟3:調(diào)用ExpressionBasedPreInvocationAdvice類中的before方法,filter結(jié)果為true則保留元素,為false則刪除元素
				.filter((auth) -> this.preInvocationAdvice.before(auth, invocation, preAttr))
				.switchIfEmpty(Mono.defer(() -> Mono.error(new AccessDeniedException("Denied"))));
}

對關(guān)鍵步驟3進行補充說明:

  • 當前的安全上下文中不存在認證信息(Authentication),即 ReactiveSecurityContextHolder.getContext().map(SecurityContext::getAuthentication) 返回空的 Mono 對象。
  • 調(diào)用 preInvocationAdvice.before(auth, invocation, preAttr) 方法返回 false,即預(yù)授權(quán)邏輯拒絕了訪問請求。
  • 在這兩種情況下,都會使用 Mono.error(new AccessDeniedException(“Denied”)) 創(chuàng)建一個錯誤的 Mono 對象,并通過 switchIfEmpty 方法替換之前的空 Mono 對象,從而觸發(fā)異常并拋出 AccessDeniedException。

二、PrePostAnnotationSecurityMetadataSource類

類的繼承關(guān)系

PrePostAnnotationSecuirtyMetadataSource繼承實現(xiàn)類

作用

  • 解析注解:它解析方法上的PreAuthorize和PostAuthorize等注解,提取其中的權(quán)限表達式、角色信息等。
  • 提供權(quán)限驗證元數(shù)據(jù):根據(jù)解析得到的注解信息,PrePostAnnotationSecurityMetadataSource提供相應(yīng)的權(quán)限驗證元數(shù)據(jù)。這些元數(shù)據(jù)通常是ConfigAttribute對象的集合,每個ConfigAttribute表示一個權(quán)限驗證的配置。
  • 支持方法級別的權(quán)限驗證:通過為方法提供權(quán)限驗證元數(shù)據(jù),PrePostAnnotationSecurityMetadataSource支持在方法級別對權(quán)限進行驗證。這使得開發(fā)者可以在方法執(zhí)行前后定義細粒度的權(quán)限控制邏輯。
  • 與其他組件配合使用:PrePostAnnotationSecurityMetadataSource通常與其他Spring Security的組件(如AccessDecisionManager、MethodSecurityInterceptor等)配合使用,以實現(xiàn)方法級別的權(quán)限驗證。

源碼分析

// 獲取@PreAuthorize相關(guān)源碼部分展示
public class PrePostAnnotationSecurityMetadataSource extends AbstractMethodSecurityMetadataSource {
	private final PrePostInvocationAttributeFactory attributeFactory;
	public PrePostAnnotationSecurityMetadataSource(PrePostInvocationAttributeFactory attributeFactory) {
		this.attributeFactory = attributeFactory;
	}
	// PrePostAdviceReactiveMethodInterceptor invoke方法中調(diào)用該方法獲取attributes
	@Override
	public Collection<ConfigAttribute> getAttributes(Method method, Class<?> targetClass) {
		if (method.getDeclaringClass() == Object.class) {
			return Collections.emptyList();
		}
		PreAuthorize preAuthorize = findAnnotation(method, targetClass, PreAuthorize.class);
		if (preFilter == null && preAuthorize == null && postFilter == null && postAuthorize == null) {
			// There is no meta-data so return
			return Collections.emptyList();
		}
		String filterObject = (preFilter != null) ? preFilter.filterTarget() : null;
		// 獲取@PreAuthorize注解的表達式
		String preAuthorizeAttribute = (preAuthorize != null) ? preAuthorize.value() : null;
		ArrayList<ConfigAttribute> attrs = new ArrayList<>(2);
		// 關(guān)鍵步驟1:創(chuàng)建PreAuthorize對應(yīng)的ConfigAttribute
		PreInvocationAttribute pre = this.attributeFactory.createPreInvocationAttribute(preFilterAttribute,
				filterObject, preAuthorizeAttribute);
		if (pre != null) {
			attrs.add(pre);
		}
		// 將容器的容量調(diào)整為當前元素的數(shù)量
		attrs.trimToSize();
		return attrs;
	}
}
// 解析注解中的表達式,創(chuàng)建相應(yīng)的注解屬性對象
public class ExpressionBasedAnnotationAttributeFactory implements PrePostInvocationAttributeFactory {
	private final Object parserLock = new Object();
	private ExpressionParser parser;
	// 對應(yīng)下方代碼的DefaultMethodSecurityExpressionHandler
	private MethodSecurityExpressionHandler handler;
	public ExpressionBasedAnnotationAttributeFactory(MethodSecurityExpressionHandler handler) {
		this.handler = handler;
	}
    // param: preAuthorizeAttribute 獲取到的@PreAuthorize注解的表達式
	@Override
	public PreInvocationAttribute createPreInvocationAttribute(String preFilterAttribute, String filterObject,
			String preAuthorizeAttribute) {
		try {
		    // SpEL表達式解析器
			ExpressionParser parser = getParser();
			// 關(guān)鍵步驟
			Expression preAuthorizeExpression = (preAuthorizeAttribute != null)
					? parser.parseExpression(preAuthorizeAttribute) : parser.parseExpression("permitAll");
			Expression preFilterExpression = (preFilterAttribute != null) ? parser.parseExpression(preFilterAttribute)
					: null;
			// 關(guān)鍵步驟
			return new 
		PreInvocationExpressionAttribute(preFilterExpression, filterObject, preAuthorizeExpression);
		}
		catch (ParseException ex) {
			throw new IllegalArgumentException("Failed to parse expression '" + ex.getExpressionString() + "'", ex);
		}
	}
}

三、ExpressionBasedPreInvocationAdvice類

作用

解析@PreAuthorize中的SpEL表達式

源碼分析

// 源碼存在部分刪減,僅展示分析與@PreAuthorize相關(guān)的內(nèi)容
public class ExpressionBasedPreInvocationAdvice implements PreInvocationAuthorizationAdvice {
    // 關(guān)鍵類 第四點有對該類的關(guān)鍵方法進行解析
	private MethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
	@Override
	public boolean before(Authentication authentication, MethodInvocation mi, PreInvocationAttribute attr) {
		PreInvocationExpressionAttribute preAttr = (PreInvocationExpressionAttribute) attr;
		// 關(guān)鍵步驟 創(chuàng)建SpEL解析上下文
		EvaluationContext ctx = this.expressionHandler.createEvaluationContext(authentication, mi);
		Expression preAuthorize = preAttr.getAuthorizeExpression();
		// 關(guān)鍵步驟 計算表達式值
		return (preAuthorize != null) ? 
		ExpressionUtils.evaluateAsBoolean(preAuthorize, ctx) : true;
	}
}

ExpressionUtils.evaluateAsBoolean(preAuthorize, ctx方法補充說明:

根據(jù)提供的安全表達式和評估上下文 ctx 來評估安全表達式的結(jié)果,并返回一個布爾值。true,則權(quán)限校驗通過;false,則校驗失敗。

四、DefaultMethodSecurityExpressionHandler類

作用

  • 創(chuàng)建評估上下文:在安全表達式求值之前,DefaultMethodSecurityExpressionHandler 會創(chuàng)建一個評估上下文EvaluationContext對象,以提供給安全表達式進行求值。評估上下文包含了當前用戶的身份驗證信息、目標對象和方法參數(shù)等相關(guān)信息。
  • 權(quán)限注解的處理:DefaultMethodSecurityExpressionHandler 支持處理方法參數(shù)上的權(quán)限注解,例如 @PreFilter 和 @PostFilter 注解。它會將這些注解解析為相應(yīng)的安全表達式,并在評估上下文中傳遞方法參數(shù)的信息,以進行權(quán)限過濾操作。

源碼分析

public class DefaultMethodSecurityExpressionHandler extends AbstractSecurityExpressionHandler<MethodInvocation>
		implements MethodSecurityExpressionHandler {
	// 用于處理表達式中的bean對象獲取
	private BeanResolver beanResolver;
	private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
	// 這個類非常重要,下文會對這個類單獨進行解析
	private ParameterNameDiscoverer parameterNameDiscoverer = new DefaultSecurityParameterNameDiscoverer();
	private PermissionCacheOptimizer permissionCacheOptimizer = null;
	private String defaultRolePrefix = "ROLE_";
	public DefaultMethodSecurityExpressionHandler() {
	}
	/**
	 * ExpressionBasedPreInvocationAdvice的before方法中調(diào)用該方法,創(chuàng)建方法安全表達式的評估上下文
	 */
	@Override
	public final EvaluationContext createEvaluationContext(Authentication authentication, T invocation) {
		SecurityExpressionOperations root = createSecurityExpressionRoot(authentication, invocation);
		StandardEvaluationContext ctx = createEvaluationContextInternal(authentication, invocation);
		ctx.setBeanResolver(this.beanResolver);
		ctx.setRootObject(root);
		return ctx;
	}
	@Override
	public void setApplicationContext(ApplicationContext applicationContext) {
		this.beanResolver = new BeanFactoryResolver(applicationContext);
	}
	/**
	 * 在 Spring Security 中,安全表達式用于在方法級別進行訪問控制的決策。createEvaluationContextInternal方法在方法級別的安全表達式求值過程中被調(diào)用,其主要作用是創(chuàng)建一個評估上下文對象,以提供給安全表達式進行求值。
	 */
	@Override
	public StandardEvaluationContext createEvaluationContextInternal(Authentication auth, MethodInvocation mi) {
		return new MethodSecurityEvaluationContext(auth, mi, getParameterNameDiscoverer());
	}
	/**
	* 方法級別的安全表達式通常需要訪問當前用戶、目標對象和方法參數(shù)等相關(guān)     信息。createEvaluationContextInternal方法會使用 MethodSecurityExpressionRoot類的實例作為權(quán)限表達式的根對象,以便在表達式中訪問這些信息。
	*/
	@Override
	protected MethodSecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication,
			MethodInvocation invocation) {
		MethodSecurityExpressionRoot root = new MethodSecurityExpressionRoot(authentication);
		root.setThis(invocation.getThis());
		root.setPermissionEvaluator(getPermissionEvaluator());
		root.setTrustResolver(getTrustResolver());
		root.setRoleHierarchy(getRoleHierarchy());
		root.setDefaultRolePrefix(getDefaultRolePrefix());
		return root;
	}
}

MethodSecurityExpressionOperations 類進行補充說明:

MethodSecurityExpressionOperations 接口定義了一組方法,用于在安全表達式中進行常見的操作和判斷,例如獲取當前用戶信息、檢查角色和權(quán)限等。下面舉例該類的部分方法:

  • boolean hasAuthority(String authority)
  • boolean hasAnyAuthority(String… authorities)
  • boolean hasRole(String role)
  • boolean hasAnyRole(String… roles)
  • boolean permitAll()
  • boolean denyAll()
  • boolean hasPermission(Object target, Object permission)

DefaultSecurityParameterNameDiscoverer 類進行補充說明: 在 Spring Security 中,當使用方法級別的注解(如 @PreAuthorize、@PostAuthorize、@PreFilter 和 @PostFilter)時,需要引用方法參數(shù)的名稱來進行安全性評估和過濾操作。但編譯器默認情況下不會在編譯過程中保留方法參數(shù)的名稱,而是使用類似 “arg0”、“arg1” 等默認名稱。DefaultSecurityParameterNameDiscoverer 的作用就是解決這個問題,它通過不同的策略來發(fā)現(xiàn)方法參數(shù)的名稱,以便在安全性注解中引用正確的參數(shù)。

到此這篇關(guān)于Java中的@PreAuthorize注解源碼解析的文章就介紹到這了,更多相關(guān)@PreAuthorize注解源碼內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Spring+Quartz實現(xiàn)動態(tài)任務(wù)調(diào)度詳解

    Spring+Quartz實現(xiàn)動態(tài)任務(wù)調(diào)度詳解

    這篇文章主要介紹了Spring+Quartz實現(xiàn)動態(tài)任務(wù)調(diào)度詳解,最近經(jīng)?;趕pring?boot寫定時任務(wù),并且是使用注解的方式進行實現(xiàn),分成的方便將自己的類注入spring容器,需要的朋友可以參考下
    2024-01-01
  • Java雙色球系統(tǒng)開發(fā)詳解

    Java雙色球系統(tǒng)開發(fā)詳解

    這篇文章主要為大家詳細介紹了Java雙色球系統(tǒng)的開發(fā),超級簡單的邏輯,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • 詳解java集成支付寶支付接口(JSP+支付寶20160912)

    詳解java集成支付寶支付接口(JSP+支付寶20160912)

    本篇文章主要介紹了java集成支付寶支付接口,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-12-12
  • Gateway集成Netty服務(wù)的配置加載詳解

    Gateway集成Netty服務(wù)的配置加載詳解

    這篇文章主要為大家介紹了Gateway集成Netty服務(wù)的配置加載詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-02-02
  • Java中Retry方法的簡單實現(xiàn)

    Java中Retry方法的簡單實現(xiàn)

    這篇文章主要介紹了Java中Retry方法的簡單實現(xiàn),Retry主要是利用Java的lambda表達式和線程接口實現(xiàn)有返回值和無返回值的重試,思考了下就寫了一個簡易Retry功能分享出來,需要的朋友可以參考下
    2024-01-01
  • IDEA JarEditor編輯jar包方式(直接新增,修改,刪除jar包內(nèi)的class文件)

    IDEA JarEditor編輯jar包方式(直接新增,修改,刪除jar包內(nèi)的class文件)

    文章主要介紹了如何使用IDEA的JarEditor插件直接修改jar包內(nèi)的class文件,而不需要手動解壓、反編譯和重新打包,通過該插件,可以更方便地進行jar包的修改和測試
    2025-01-01
  • 超詳細講解Java秒殺項目用戶驗證模塊的實現(xiàn)

    超詳細講解Java秒殺項目用戶驗證模塊的實現(xiàn)

    這是一個主要使用java開發(fā)的秒殺系統(tǒng),項目比較大,所以本篇只實現(xiàn)了用戶驗證模塊,代碼非常詳盡,感興趣的朋友快來看看
    2022-03-03
  • Java多線程文件分片下載實現(xiàn)的示例代碼

    Java多線程文件分片下載實現(xiàn)的示例代碼

    這篇文章主要介紹了Java多線程文件分片下載實現(xiàn)的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-03-03
  • Spring裝配Bean之用Java代碼安裝配置bean詳解

    Spring裝配Bean之用Java代碼安裝配置bean詳解

    這篇文章主要給大家介紹了關(guān)于Spring裝配Bean之用Java代碼安裝配置bean的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用spring具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧。
    2017-10-10
  • Java中JSONObject和Map<String,?Object>的轉(zhuǎn)換方法

    Java中JSONObject和Map<String,?Object>的轉(zhuǎn)換方法

    平時對接口時,經(jīng)常遇到j(luò)son字符串和map對象之間的交互,這篇文章主要給大家介紹了關(guān)于Java中JSONObject和Map<String,?Object>的轉(zhuǎn)換方法,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2024-07-07

最新評論