亚洲精品久久久中文字幕-亚洲精品久久片久久-亚洲精品久久青草-亚洲精品久久婷婷爱久久婷婷-亚洲精品久久午夜香蕉

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

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

瀏覽:76日期:2023-03-02 10:16:54

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

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

@Component//用于設(shè)置受保護(hù)資源的權(quán)限信息的數(shù)據(jù)源public class MyFilterInvocationSecurityMetadataSource implementsFilterInvocationSecurityMetadataSource { @Bean public AntPathMatcher getAntPathMatcher(){return new AntPathMatcher(); }@Autowired //獲取數(shù)據(jù)庫(kù)中的保存的url Url表只儲(chǔ)存受保護(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;//獲取用戶請(qǐng)求的UrlString url = fi.getRequestUrl();//先到數(shù)據(jù)庫(kù)獲取受權(quán)限控制的UrlList<Rights> us = rightsMapper.queryAll();//用于儲(chǔ)存用戶請(qǐng)求的Url能夠訪問的角色Collection<ConfigAttribute> rs=new ArrayList<ConfigAttribute>();for(Rights u:us){ if (u.getUrl() != null) {//逐一判斷用戶請(qǐng)求的Url是否和數(shù)據(jù)庫(kù)中受權(quán)限控制的Url有匹配的if (antPathMatcher.match(u.getUrl(), url)) { //如果有則將可以訪問該Url的角色儲(chǔ)存到Collection<ConfigAttribute> rs.add(rightsMapper.queryById(u.getId()));} }}if(rs.size()>0) { return rs;}//沒有匹配到,就說明此資源沒有被控制,所有人都可以訪問,返回null即可,返回null則不會(huì)進(jìn)入之后的decide方法return null; } @Override public Collection<ConfigAttribute> getAllConfigAttributes() {// TODO 自動(dòng)生成的方法存根return null; } @Override public boolean supports(Class<?> clazz) {// TODO 自動(dòng)生成的方法存根return FilterInvocation.class.isAssignableFrom(clazz); }}

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

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

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

內(nèi)容:

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

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

@Component//用于設(shè)置判斷當(dāng)前用戶是否可以訪問被保護(hù)資源的邏輯public class MyAccessDecisionManager implements AccessDecisionManager { @Override /* * @param 請(qǐng)求該保護(hù)資源的用戶對(duì)象 * @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)前用戶是否有對(duì)應(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)) { // 匹配到有對(duì)應(yīng)角色,則允許通過 return;} }}// 該url有配置權(quán)限,但是當(dāng)前登錄用戶沒有匹配到對(duì)應(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()//對(duì)請(qǐng)求授權(quán).antMatchers('/**').permitAll().anyRequest()//任何請(qǐng)求.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(); }}

配置如下代碼:

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

至此完成所有配置!!!

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

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

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

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

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

解決方法有兩種:

第一種方法:

默認(rèn)rejectPublicInvocations為false。

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

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

第二種方法:

配置rejectPublicInvocations為true

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

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

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

package org.springframework.security.access.intercept;/** * 對(duì)安全對(duì)象(訪問請(qǐng)求+用戶主體)攔截的抽象類源碼 */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資源> 對(duì)應(yīng)的 <角色列表>Collection<ConfigAttribute> attributes = this.obtainSecurityMetadataSource().getAttributes(object);// 框架在此處判斷URL資源對(duì)應(yīng)的角色列表是否為空if (attributes == null || attributes.isEmpty()) {// rejectPublicInvocations默認(rèn)為false // 可以配置為true,即角色列表為空的時(shí)候不進(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)限對(duì)象為nullif (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)限對(duì)象,特殊場(chǎng)景使用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-invocationreturn 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-invocationreturn new InterceptorStatusToken(origCtx, true, attributes, object);}}// ... 其他方法略}

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持好吧啦網(wǎng)。

標(biāo)簽: Spring
相關(guān)文章:
主站蜘蛛池模板: 免费无遮挡十八女禁污污网站 | 欧美黄色大片 | 一区二区三区网站在线免费线观看 | 91国视频在线观看 | 国产免费黄色大片 | 99久久久国产精品免费牛牛四川 | 亚洲第一国产 | 99riav国产精品 | 欧美日韩国产高清视频 | 亚洲第一a亚洲 | 国产品精人成福利视频 | 91在线视频免费播放 | 美国一级大黄一片免费网站 | 国产欧美国产精品第一区 | 优看影院污 | 中文字幕无线码一区二区三区 | 欧美性黑吊xxx | 大片免费看大片费看大片 | 国产精品1区2区3区在线播放 | 丝袜美腿亚洲综合 | 国产精品资源手机在线播放 | 在线视频一区二区日韩国产 | 亚洲欧美一区二区三区不卡 | 国产麻豆精品免费密入口 | 国产高清在线精品 | 国产综合免费视频 | 亚洲欧美日韩中文字幕在线一 | 普通话对白国产情侣自啪 | 1000部末满18在线观看黄 | 中国china体内裑精亚洲毛片 | 国产真实搭讪系列 | 国产一区 在线视频 | 2021年韩国r级理论片在线观看 | 国产精品免费一区二区区 | 性欧美一级毛片欧美片 | 色婷婷在线影院 | 久久国产精品女 | 久久9966精品国产免费 | 龙口护士门91午夜国产在线 | 国产综合精品久久亚洲 | 免费视频精品一区二区三区 |