真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

怎么在springsecurity中動(dòng)態(tài)配置url權(quán)限

這期內(nèi)容當(dāng)中小編將會(huì)給大家?guī)碛嘘P(guān)怎么在spring security中動(dòng)態(tài)配置url權(quán)限,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

創(chuàng)新互聯(lián)公司專業(yè)為企業(yè)提供同安網(wǎng)站建設(shè)、同安做網(wǎng)站、同安網(wǎng)站設(shè)計(jì)、同安網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁設(shè)計(jì)與制作、同安企業(yè)網(wǎng)站模板建站服務(wù),10年同安做網(wǎng)站經(jīng)驗(yàn),不只是建網(wǎng)站,更提供有價(jià)值的思路和整體網(wǎng)絡(luò)服務(wù)。

spring security 授權(quán)回顧

spring security 通過FilterChainProxy作為注冊到web的filter,F(xiàn)ilterChainProxy里面一次包含了內(nèi)置的多個(gè)過濾器,我們首先需要了解spring security內(nèi)置的各種filter:

AliasFilter ClassNamespace Element or Attribute
CHANNEL_FILTERChannelProcessingFilterhttp/intercept-url@requires-channel
SECURITY_CONTEXT_FILTERSecurityContextPersistenceFilterhttp
CONCURRENT_SESSION_FILTERConcurrentSessionFiltersession-management/concurrency-control
HEADERS_FILTERHeaderWriterFilterhttp/headers
CSRF_FILTERCsrfFilterhttp/csrf
LOGOUT_FILTERLogoutFilterhttp/logout
X509_FILTERX509AuthenticationFilterhttp/x509
PRE_AUTH_FILTERAbstractPreAuthenticatedProcessingFilter SubclassesN/A
CAS_FILTERCasAuthenticationFilterN/A
FORM_LOGIN_FILTERUsernamePasswordAuthenticationFilterhttp/form-login
BASIC_AUTH_FILTERBasicAuthenticationFilterhttp/http-basic
SERVLET_API_SUPPORT_FILTERSecurityContextHolderAwareRequestFilterhttp/@servlet-api-provision
JAAS_API_SUPPORT_FILTERJaasApiIntegrationFilterhttp/@jaas-api-provision
REMEMBER_ME_FILTERRememberMeAuthenticationFilterhttp/remember-me
ANONYMOUS_FILTERAnonymousAuthenticationFilterhttp/anonymous
SESSION_MANAGEMENT_FILTERSessionManagementFiltersession-management
EXCEPTION_TRANSLATION_FILTERExceptionTranslationFilterhttp
FILTER_SECURITY_INTERCEPTORFilterSecurityInterceptorhttp
SWITCH_USER_FILTERSwitchUserFilterN/A

最重要的是FilterSecurityInterceptor,該過濾器實(shí)現(xiàn)了主要的鑒權(quán)邏輯,最核心的代碼在這里:

protected InterceptorStatusToken beforeInvocation(Object object) { 
 // 獲取訪問URL所需權(quán)限
 Collection attributes = this.obtainSecurityMetadataSource()
 .getAttributes(object);

 
 Authentication authenticated = authenticateIfRequired();

 // 通過accessDecisionManager鑒權(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
 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);
 }
 }

從上面可以看出,要實(shí)現(xiàn)動(dòng)態(tài)鑒權(quán),可以從兩方面著手:

  • 自定義SecurityMetadataSource,實(shí)現(xiàn)從數(shù)據(jù)庫加載ConfigAttribute

  • 另外就是可以自定義accessDecisionManager,官方的UnanimousBased其實(shí)足夠使用,并且他是基于AccessDecisionVoter來實(shí)現(xiàn)權(quán)限認(rèn)證的,因此我們只需要自定義一個(gè)AccessDecisionVoter就可以了

下面來看分別如何實(shí)現(xiàn)。

自定義AccessDecisionManager

官方的三個(gè)AccessDecisionManager都是基于AccessDecisionVoter來實(shí)現(xiàn)權(quán)限認(rèn)證的,因此我們只需要自定義一個(gè)AccessDecisionVoter就可以了。

自定義主要是實(shí)現(xiàn)AccessDecisionVoter接口,我們可以仿照官方的RoleVoter實(shí)現(xiàn)一個(gè):

public class RoleBasedVoter implements AccessDecisionVoter {
 @Override
 public boolean supports(ConfigAttribute attribute) {
 return true;
 }

 @Override
 public int vote(Authentication authentication, Object object, Collection attributes) {
 if(authentication == null) {
 return ACCESS_DENIED;
 }
 int result = ACCESS_ABSTAIN;
 Collection authorities = extractAuthorities(authentication);
 for (ConfigAttribute attribute : attributes) {
 if(attribute.getAttribute()==null){
 continue;
 }
 if (this.supports(attribute)) {
 result = ACCESS_DENIED;

 // Attempt to find a matching granted authority
 for (GrantedAuthority authority : authorities) {
  if (attribute.getAttribute().equals(authority.getAuthority())) {
  return ACCESS_GRANTED;
  }
 }
 }
 }
 return result;
 }

 Collection extractAuthorities(
 Authentication authentication) {
 return authentication.getAuthorities();
 }

 @Override
 public boolean supports(Class clazz) {
 return true;
 }
}

如何加入動(dòng)態(tài)權(quán)限呢?

vote(Authentication authentication, Object object, Collection attributes)里的Object object的類型是FilterInvocation,可以通過getRequestUrl獲取當(dāng)前請求的URL:

 FilterInvocation fi = (FilterInvocation) object;
 String url = fi.getRequestUrl();

因此這里擴(kuò)展空間就大了,可以從DB動(dòng)態(tài)加載,然后判斷URL的ConfigAttribute就可以了。

如何使用這個(gè)RoleBasedVoter呢?在configure里使用accessDecisionManager方法自定義,我們還是使用官方的UnanimousBased,然后將自定義的RoleBasedVoter加入即可。

@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
 @Override
 protected void configure(HttpSecurity http) throws Exception {
 http
 .addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class)
 .exceptionHandling()
 .authenticationEntryPoint(problemSupport)
 .accessDeniedHandler(problemSupport)
 .and()
 .csrf()
 .disable()
 .headers()
 .frameOptions()
 .disable()
 .and()
 .sessionManagement()
 .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
 .and()
 .authorizeRequests()
 // 自定義accessDecisionManager
 .accessDecisionManager(accessDecisionManager()) 
 .and()
 .apply(securityConfigurerAdapter());

 }

 @Bean
 public AccessDecisionManager accessDecisionManager() {
 List> decisionVoters
 = Arrays.asList(
 new WebExpressionVoter(),
 // new RoleVoter(),
 new RoleBasedVoter(),
 new AuthenticatedVoter());
 return new UnanimousBased(decisionVoters);
 }

自定義SecurityMetadataSource

自定義FilterInvocationSecurityMetadataSource只要實(shí)現(xiàn)接口即可,在接口里從DB動(dòng)態(tài)加載規(guī)則。

為了復(fù)用代碼里的定義,我們可以將代碼里生成的SecurityMetadataSource帶上,在構(gòu)造函數(shù)里傳入默認(rèn)的FilterInvocationSecurityMetadataSource。

public class AppFilterInvocationSecurityMetadataSource implements org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource {
 private FilterInvocationSecurityMetadataSource superMetadataSource;
 @Override
 public Collection getAllConfigAttributes() {
 return null;
 }

 public AppFilterInvocationSecurityMetadataSource(FilterInvocationSecurityMetadataSource expressionBasedFilterInvocationSecurityMetadataSource){
  this.superMetadataSource = expressionBasedFilterInvocationSecurityMetadataSource;
  // TODO 從數(shù)據(jù)庫加載權(quán)限配置
 }

 private final AntPathMatcher antPathMatcher = new AntPathMatcher();
 
 // 這里的需要從DB加載
 private final Map urlRoleMap = new HashMap(){{
 put("/open/**","ROLE_ANONYMOUS");
 put("/health","ROLE_ANONYMOUS");
 put("/restart","ROLE_ADMIN");
 put("/demo","ROLE_USER");
 }};

 @Override
 public Collection getAttributes(Object object) throws IllegalArgumentException {
 FilterInvocation fi = (FilterInvocation) object;
 String url = fi.getRequestUrl();
 for(Map.Entry entry:urlRoleMap.entrySet()){
  if(antPathMatcher.match(entry.getKey(),url)){
  return SecurityConfig.createList(entry.getValue());
  }
 }
 // 返回代碼定義的默認(rèn)配置
 return superMetadataSource.getAttributes(object);
 }

 @Override
 public boolean supports(Class clazz) {
 return FilterInvocation.class.isAssignableFrom(clazz);
 }
}

怎么使用?和accessDecisionManager不一樣,ExpressionUrlAuthorizationConfigurer 并沒有提供set方法設(shè)置FilterSecurityInterceptor的FilterInvocationSecurityMetadataSource,how to do?

發(fā)現(xiàn)一個(gè)擴(kuò)展方法withObjectPostProcessor,通過該方法自定義一個(gè)處理FilterSecurityInterceptor類型的ObjectPostProcessor就可以修改FilterSecurityInterceptor。

@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
 @Override
 protected void configure(HttpSecurity http) throws Exception {
 http
  .addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class)
  .exceptionHandling()
  .authenticationEntryPoint(problemSupport)
  .accessDeniedHandler(problemSupport)
 .and()
  .csrf()
  .disable()
  .headers()
  .frameOptions()
  .disable()
 .and()
  .sessionManagement()
  .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
 .and()
  .authorizeRequests()
  // 自定義FilterInvocationSecurityMetadataSource
  .withObjectPostProcessor(new ObjectPostProcessor() {
  @Override
  public  O postProcess(
   O fsi) {
   fsi.setSecurityMetadataSource(mySecurityMetadataSource(fsi.getSecurityMetadataSource()));
   return fsi;
  }
  })
 .and()
  .apply(securityConfigurerAdapter());
 }

 @Bean
 public AppFilterInvocationSecurityMetadataSource mySecurityMetadataSource(FilterInvocationSecurityMetadataSource filterInvocationSecurityMetadataSource) {
 AppFilterInvocationSecurityMetadataSource securityMetadataSource = new AppFilterInvocationSecurityMetadataSource(filterInvocationSecurityMetadataSource);
 return securityMetadataSource;
}

上述就是小編為大家分享的怎么在spring security中動(dòng)態(tài)配置url權(quán)限了,如果剛好有類似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。


網(wǎng)站標(biāo)題:怎么在springsecurity中動(dòng)態(tài)配置url權(quán)限
瀏覽地址:http://weahome.cn/article/jjeicp.html

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部