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

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

怎么在springsecurity中動態(tài)配置url權限-創(chuàng)新互聯(lián)

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

讓客戶滿意是我們工作的目標,不斷超越客戶的期望值來自于我們對這個行業(yè)的熱愛。我們立志把好的技術通過有效、簡單的方式提供給客戶,將通過不懈努力成為客戶在信息化領域值得信任、有價值的長期合作伙伴,公司提供的服務項目有:國際域名空間、虛擬空間、營銷軟件、網站建設、蘭陵網站維護、網站推廣。

spring security 授權回顧

spring security 通過FilterChainProxy作為注冊到web的filter,F(xiàn)ilterChainProxy里面一次包含了內置的多個過濾器,我們首先需要了解spring security內置的各種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,該過濾器實現(xiàn)了主要的鑒權邏輯,最核心的代碼在這里:

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

 
 Authentication authenticated = authenticateIfRequired();

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

從上面可以看出,要實現(xiàn)動態(tài)鑒權,可以從兩方面著手:

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

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

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

自定義AccessDecisionManager

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

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

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;
 }
}

如何加入動態(tài)權限呢?

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

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

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

如何使用這個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只要實現(xiàn)接口即可,在接口里從DB動態(tài)加載規(guī)則。

為了復用代碼里的定義,我們可以將代碼里生成的SecurityMetadataSource帶上,在構造函數(shù)里傳入默認的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ù)庫加載權限配置
 }

 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());
  }
 }
 // 返回代碼定義的默認配置
 return superMetadataSource.getAttributes(object);
 }

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

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

發(fā)現(xiàn)一個擴展方法withObjectPostProcessor,通過該方法自定義一個處理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中動態(tài)配置url權限了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注創(chuàng)新互聯(lián)行業(yè)資訊頻道。


網頁題目:怎么在springsecurity中動態(tài)配置url權限-創(chuàng)新互聯(lián)
標題路徑:http://weahome.cn/article/ddiidi.html

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部