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

springboot+springsecurity如何實現(xiàn)動態(tài)url細(xì)粒度權(quán)限認(rèn)證

 更新時間:2021年06月22日 11:55:25   作者:佛說  
這篇文章主要介紹了springboot+springsecurity如何實現(xiàn)動態(tài)url細(xì)粒度權(quán)限認(rèn)證的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

謹(jǐn)記:Url表只儲存受保護(hù)的資源,不在表里的資源說明不受保護(hù),任何人都可以訪問

1、MyFilterInvocationSecurityMetadataSource 類判斷該訪問路徑是否被保護(hù)

@Component
//用于設(shè)置受保護(hù)資源的權(quán)限信息的數(shù)據(jù)源
public class MyFilterInvocationSecurityMetadataSource implements
        FilterInvocationSecurityMetadataSource {
    @Bean
    public AntPathMatcher getAntPathMatcher(){
        return new AntPathMatcher();
    }    
    @Autowired  
	//獲取數(shù)據(jù)庫中的保存的url  Url表只儲存受保護(hù)的資源,不在表里的資源說明不受保護(hù),任何人都可以訪問
    private RightsMapper rightsMapper; 
    
    @Autowired
    private AntPathMatcher antPathMatcher;
    @Override
    /*
     * @param 被調(diào)用的保護(hù)資源
     * @return 返回能夠訪問該保護(hù)資源的角色集合,如果沒有,則應(yīng)返回空集合。
     */
    public Collection<ConfigAttribute> getAttributes(Object object)
            throws IllegalArgumentException {
        FilterInvocation fi = (FilterInvocation) object;
        //獲取用戶請求的Url
        String url = fi.getRequestUrl();
        //先到數(shù)據(jù)庫獲取受權(quán)限控制的Url
        List<Rights> us = rightsMapper.queryAll();
        //用于儲存用戶請求的Url能夠訪問的角色
        Collection<ConfigAttribute> rs=new ArrayList<ConfigAttribute>();
        for(Rights u:us){
            if (u.getUrl() != null) {
                //逐一判斷用戶請求的Url是否和數(shù)據(jù)庫中受權(quán)限控制的Url有匹配的
                if (antPathMatcher.match(u.getUrl(), url)) {
                    //如果有則將可以訪問該Url的角色儲存到Collection<ConfigAttribute>
                    rs.add(rightsMapper.queryById(u.getId()));
                }
            }
        }
        if(rs.size()>0) {
            return rs;
        }
        //沒有匹配到,就說明此資源沒有被控制,所有人都可以訪問,返回null即可,返回null則不會進(jìn)入之后的decide方法
        return null;
    }
    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        // TODO 自動生成的方法存根
        return null;
    }
    @Override
    public boolean supports(Class<?> clazz) {
        // TODO 自動生成的方法存根
        return FilterInvocation.class.isAssignableFrom(clazz);
    }
}

rights表中的部分內(nèi)容:

表結(jié)構(gòu)

在這里插入圖片描述

內(nèi)容:

在這里插入圖片描述

2、MyAccessDecisionManager 類判斷該用戶是否有權(quán)限訪問

@Component
//用于設(shè)置判斷當(dāng)前用戶是否可以訪問被保護(hù)資源的邏輯
public class MyAccessDecisionManager implements AccessDecisionManager {
    @Override
    /*
     * @param 請求該保護(hù)資源的用戶對象
     * @param 被調(diào)用的保護(hù)資源
     * @param 有權(quán)限調(diào)用該資源的集合
     */
    public void decide(Authentication authentication, Object object,
                       Collection<ConfigAttribute> configAttributes)
            throws AccessDeniedException, InsufficientAuthenticationException {
        Iterator<ConfigAttribute> ite = configAttributes.iterator();
        //遍歷configAttributes,查看當(dāng)前用戶是否有對應(yīng)的權(quán)限訪問該保護(hù)資源
        while (ite.hasNext()) {
            ConfigAttribute ca = ite.next();
            String needRole = ca.getAttribute();
            for (GrantedAuthority ga : authentication.getAuthorities()) {
                if (ga.getAuthority().equals(needRole)) {
                    // 匹配到有對應(yīng)角色,則允許通過
                    return;
                }
            }
        }
        // 該url有配置權(quán)限,但是當(dāng)前登錄用戶沒有匹配到對應(yīng)權(quán)限,則禁止訪問
        throw new AccessDeniedException("not allow");
    }
    @Override
    public boolean supports(ConfigAttribute attribute) {
        return true;
    }
    @Override
    public boolean supports(Class<?> clazz) {
        return true;
    }
}

3、在SecurityConfig 類中配置說明

@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    MyUserDetailsService myUserDetailsService;
    @Autowired
    private SendSmsSecurityConfig sendSmsSecurityConfig;
    @Autowired
    private MyAccessDecisionManager myAccessDecisionManager;
    @Autowired
    private MyFilterInvocationSecurityMetadataSource myFilterInvocationSecurityMetadataSource;
    //加密機(jī)制
    @Bean
    public PasswordEncoder passwordEncoder() {
        return NoOpPasswordEncoder.getInstance(); // 不加密
    }
    //認(rèn)證
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(myUserDetailsService)
                .passwordEncoder(passwordEncoder());
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()//對請求授權(quán)
                .antMatchers("/**").permitAll()
                .anyRequest()//任何請求
                .authenticated()//登錄后訪問
                .withObjectPostProcessor(
                        new ObjectPostProcessor<FilterSecurityInterceptor>() {
                            @Override
                            public <O extends FilterSecurityInterceptor> O postProcess(
                                    O fsi) {
                                fsi.setSecurityMetadataSource(myFilterInvocationSecurityMetadataSource);
                                fsi.setAccessDecisionManager(myAccessDecisionManager);
                                return fsi;
                            }
                        })
                .and().csrf().disable();
    }
}

配置如下代碼:

在這里插入圖片描述

至此完成所有配置!??!

SpringSecurity解決公共接口自定義權(quán)限驗證失效問題,和源碼分析

背景:

自定義權(quán)限認(rèn)證,一部分接口必須要有相應(yīng)的角色權(quán)限,一部分接口面向所有訪問者,一部分接口任何人都不能訪問。但是在使用 SpringSecurity的過程中發(fā)現(xiàn),框架會將沒有指定角色列表的URL資源直接放行,不做攔截。

用戶登錄認(rèn)證成功后,攜帶Token訪問URL資源,spring security 根據(jù)Token(請求頭Authorization中)來分辨不同用戶。

用戶權(quán)限數(shù)據(jù)源是一個Map:以 URL資源為Key,以有權(quán)訪問的Key的角色列表為Value。

使用時發(fā)現(xiàn)當(dāng)一個接口有Key,但是Value為空或null時,spring security 框架自動放行,導(dǎo)致了權(quán)限失效問題。

解決方法有兩種:

第一種方法:

默認(rèn)rejectPublicInvocations為false。

對需要控制權(quán)限的URL資源添加標(biāo)志,以防止roleList為空,跳過了權(quán)限驗證.

公共權(quán)限設(shè)置為null,不進(jìn)行權(quán)限驗證

第二種方法:

配置rejectPublicInvocations為true

此后roleList為空,或者沒有找到URL資源時,都為拒絕訪問

需要控制權(quán)限的URL資源,即使對應(yīng)角色為空,也會進(jìn)行權(quán)限驗證

公共權(quán)限設(shè)置為所有角色和匿名角色,不進(jìn)行權(quán)限驗證

package org.springframework.security.access.intercept;
/**
 * 對安全對象(訪問請求+用戶主體)攔截的抽象類源碼
 */
public abstract class AbstractSecurityInterceptor implements InitializingBean, ApplicationEventPublisherAware, MessageSourceAware {
	// ... 其他方法省略
	
	protected InterceptorStatusToken beforeInvocation(Object object) {
		Assert.notNull(object, "Object was null");
		final boolean debug = logger.isDebugEnabled();
		if (!getSecureObjectClass().isAssignableFrom(object.getClass())) {
			throw new IllegalArgumentException(
					"Security invocation attempted for object "
							+ object.getClass().getName()
							+ " but AbstractSecurityInterceptor only configured to support secure objects of type: "
							+ getSecureObjectClass());
		}
		// 從權(quán)限數(shù)據(jù)源獲取了當(dāng)前 <URL資源> 對應(yīng)的 <角色列表>
		Collection<ConfigAttribute> attributes = this.obtainSecurityMetadataSource().getAttributes(object);
				
		// 框架在此處判斷URL資源對應(yīng)的角色列表是否為空
		if (attributes == null || attributes.isEmpty()) {
			// rejectPublicInvocations默認(rèn)為false 
			// 可以配置為true,即角色列表為空的時候不進(jìn)行放行
			if (rejectPublicInvocations) {
				throw new IllegalArgumentException(
						"Secure object invocation "
								+ object
								+ " was denied as public invocations are not allowed via this interceptor. "
								+ "This indicates a configuration error because the "
								+ "rejectPublicInvocations property is set to 'true'");
			}
			if (debug) {
				logger.debug("Public object - authentication not attempted");
			}
			publishEvent(new PublicInvocationEvent(object));
			return null; // no further work post-invocation
		}
		if (debug) {
			logger.debug("Secure object: " + object + "; Attributes: " + attributes);
		}
		
		// 如果當(dāng)前用戶權(quán)限對象為null
		if (SecurityContextHolder.getContext().getAuthentication() == null) {
			credentialsNotFound(messages.getMessage(
					"AbstractSecurityInterceptor.authenticationNotFound",
					"An Authentication object was not found in the SecurityContext"),
					object, attributes);
		}
		Authentication authenticated = authenticateIfRequired();
		// Attempt authorization,此處調(diào)用accessDecisionManager 進(jìn)行鑒權(quán)
		try {
			this.accessDecisionManager.decide(authenticated, object, attributes);
		}
		catch (AccessDeniedException accessDeniedException) {
			publishEvent(new AuthorizationFailureEvent(object, attributes, authenticated,
					accessDeniedException));
			throw accessDeniedException;
		}
		if (debug) {
			logger.debug("Authorization successful");
		}
		if (publishAuthorizationSuccess) {
			publishEvent(new AuthorizedEvent(object, attributes, authenticated));
		}
		// Attempt to run as a different user,這里可以另外配置或修改用戶的權(quán)限對象,特殊場景使用
		Authentication runAs = this.runAsManager.buildRunAs(authenticated, object,
				attributes);
		if (runAs == null) {
			if (debug) {
				logger.debug("RunAsManager did not change Authentication object");
			}
			// no further work post-invocation
			return new InterceptorStatusToken(SecurityContextHolder.getContext(), false,
					attributes, object);
		}
		else {
			if (debug) {
				logger.debug("Switching to RunAs Authentication: " + runAs);
			}
			SecurityContext origCtx = SecurityContextHolder.getContext();
			SecurityContextHolder.setContext(SecurityContextHolder.createEmptyContext());
			SecurityContextHolder.getContext().setAuthentication(runAs);
			// need to revert to token.Authenticated post-invocation
			return new InterceptorStatusToken(origCtx, true, attributes, object);
		}
	}
	// ... 其他方法略
}

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Spring Cloud工程搭建過程詳解

    Spring Cloud工程搭建過程詳解

    文章介紹了如何使用父子工程搭建SpringCloud項目,包括創(chuàng)建父工程和子項目,以及管理依賴版本,感興趣的朋友一起看看吧
    2025-02-02
  • mybatis-plus分頁無效問題解決

    mybatis-plus分頁無效問題解決

    本文主要介紹了mybatis-plus分頁無效問題解決,原因是配置分頁插件的版本問題,舊版本和新版本的MyBatis-Plus需要不同的分頁配置,感興趣的可以了解一下
    2025-03-03
  • Java面試常考之ConcurrentHashMap多線程擴(kuò)容機(jī)制詳解

    Java面試??贾瓹oncurrentHashMap多線程擴(kuò)容機(jī)制詳解

    幾乎所有的后端技術(shù)面試官都要在?ConcurrentHashMap?技術(shù)的使用和原理方面對小伙伴們進(jìn)行刁難,本文主要來和大家聊聊ConcurrentHashMap多線程的擴(kuò)容機(jī)制,希望對大家有所幫助
    2023-05-05
  • Maven引入外部jar的幾種方法(小結(jié))

    Maven引入外部jar的幾種方法(小結(jié))

    這篇文章主要介紹了Maven引入外部jar的幾種方法(小結(jié)),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-08-08
  • Redis介紹和使用場景詳解

    Redis介紹和使用場景詳解

    這篇文章主要為大家詳細(xì)介紹了Redis介紹和使用場景,需要的朋友可以參考,具體內(nèi)容如下
    2018-04-04
  • Stream流排序數(shù)組和List?詳解

    Stream流排序數(shù)組和List?詳解

    這篇文章主要介紹了Stream流排序數(shù)組和List?詳解,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價值,感興趣的小伙伴可以參考一下
    2022-09-09
  • Java中BufferedReader與Scanner讀入的區(qū)別詳解

    Java中BufferedReader與Scanner讀入的區(qū)別詳解

    這篇文章主要介紹了Java中BufferedReader與Scanner讀入的區(qū)別詳解,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • SpringBoot整合EasyExcel實現(xiàn)批量導(dǎo)入導(dǎo)出

    SpringBoot整合EasyExcel實現(xiàn)批量導(dǎo)入導(dǎo)出

    這篇文章主要為大家詳細(xì)介紹了SpringBoot整合EasyExcel實現(xiàn)批量導(dǎo)入導(dǎo)出功能的相關(guān)知識,文中的示例代碼講解詳細(xì),需要的小伙伴可以參考下
    2024-03-03
  • Java中如何獲取圖片文件格式(后綴)

    Java中如何獲取圖片文件格式(后綴)

    這篇文章主要介紹了Java中如何獲取圖片文件格式(后綴),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • java接口自動化測試框架及斷言詳解

    java接口自動化測試框架及斷言詳解

    這篇文章主要介紹了java接口自動化測試框架及斷言詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-07-07

最新評論