기원
표준 RABC에서 권한은 동적 구성을 지원해야합니다. 스프링 보안 기본값은 코드의 권한에 동의합니다. 실제 비즈니스 시나리오는 일반적으로 런타임의 URL에 해당하는 액세스 역할을 구성하기 위해 일반적으로 역할 액세스 권한을 동적으로 구성해야합니다.
스프링 보안을 기반 으로이 요구 사항을 달성하는 방법은 무엇입니까?
가장 쉬운 방법은 필터를 사용자 정의하여 권한 판결을 완료하는 것이지만 이는 Spring Security Framework와 분리됩니다. 스프링 보안을 기반으로 우아하게 구현하는 방법은 무엇입니까?
스프링 보안 승인 검토
Spring Security FilterChainProxy는 웹에 등록하기위한 필터로 사용됩니다. FilterChainProxy에는 한 번에 여러 개의 내장 필터가 포함되어 있습니다. 먼저 스프링 보안에 내장 된 다양한 필터를 이해해야합니다.
| 별명 | 필터 클래스 | 네임 스페이스 요소 또는 속성 |
|---|---|---|
| channel_filter | ChannelProcessingFilter | http/intercept-url@require-channel |
| Security_Context_Filter | SecurityContextPersistenceFilter | http |
| concurrent_session_filter | ConcurrentSessionFilter | 세션 관리/동시성 제어 |
| headers_filter | HeaderWriterFilter | HTTP/헤더 |
| CSRF_FILTER | csrffilter | HTTP/CSRF |
| logout_filter | 로그 아웃 필터 | HTTP/로그 아웃 |
| x509_filter | x509authenticationFilter | HTTP/x509 |
| pre_auth_filter | AbstractPreauthenticatedProcessingFilter 서브 클래스 | N/A |
| cas_filter | CasuthenticationFilter | N/A |
| form_login_filter | usernamepasswordauthenticationFilter | http/form-login |
| BASIC_AUTH_FILTER | BasicAuthenticationFilter | http/http-basic |
| servlet_api_support_filter | SecurityContexTholderaWareRequestFilter | http/@servlet-api-provision |
| jaas_api_support_filter | JaasapiintegrationFilter | http/@jaas-api-provision |
| 기억력 _me_filter | MeauthenticationFilter를 기억하십시오 | http/remember-me |
| Anonymous_Filter | AnonymousauthenticationFilter | HTTP/익명 |
| Session_Management_Filter | SessionManagementFilter | 세션 관리 |
| Exception_Translation_Filter | ExceptionTranslationFilter | http |
| filter_security_interceptor | Filtersecurity Interceptor | http |
| switch_user_filter | SwitchuserFilter | N/A |
가장 중요한 것은 주요 인증 로직을 구현하는 FiltersecurityInterceptor이며 가장 핵심 코드는 다음과 같습니다.
Protected InterceptorStatUtoken (Object Object) {// URL 컬렉션에 액세스하는 데 필요한 권한을 가져옵니다. 인증 인증 = AuthenticateIfrequired (); // accessDecisionManager를 통한 인증 {this.accessDecisionManager.docide (인증, 개체, 속성); } catch (AccessDeniedexception accessDeniedexception) {publishevent (new authorizationFailureEvent (개체, 속성, 인증, AccessDeniedException)); accessdeniedexception을 던지십시오. } if (debug) {logger.debug ( "승인 성공"); } if (publishauthorizationSuccessful ");} if (publishauthorizationSuccess) {publishevent (객체, 속성, 인증, 인증); {logger.debug (runasmanager는 인증 객체를 변경하지 않았습니다.}; securitycontextolder.setContext (); }위에서 볼 수 있듯이 동적 인증을 달성하기 위해 두 가지 측면에서 시작할 수 있습니다.
별도로 구현하는 방법을 살펴 보겠습니다.
Custom AccessDecisionManager
3 개의 공식 AccessDecisionManagers는 모두 AccessDecisionVoTer를 기반으로 권한 인증을 구현하므로 AccessDecisionVoTer를 사용자 정의하면됩니다.
사용자 정의는 주로 AccessDecisionVoTer 인터페이스를 구현합니다. 우리는 다음과 같은 공식 역할을 구현할 수 있습니다.
공개 클래스 역할 기반 VoTer는 AccessDecisionVoTer <botor> {@override public boolean supports (configattribute attribute) {return true; } @override public int vote (인증 인증, 객체 객체, 수집 <configattribute> 속성) {if (authentication == null) {return access_denied; } int result = access_abstain; 컬렉션 <? grantauthority> 당국 = 추출물 (인증)을 확장합니다. for (configattribute 속성 : 속성) {if (attribute.getAttribute () == null) {계속; } if (this.supports (attribute)) {result = access_denied; // (GranteDauthority Authority : 당국) {if (attribute.getAttribute (). equals (Authority.getAuthority ()))에 대한 부여 된 권한을 찾으려고 시도합니다. }}}} 반환 결과; } 수집 <? grantauthority> 추출물 인증 (인증 인증) {return Authentication.getAuthorities (); } @override public boolean supports (클래스 클레이즈) {return true; }}동적 권한을 추가하는 방법?
vote(Authentication authentication, Object object, Collection<ConfigAttribute> attributes) 은 filterinvocation이며 getRequestUrl을 통해 현재 요청의 URL을 얻을 수 있습니다.
FilterInvocation fi = (FilterInvocation) 객체; 문자열 url = fi.getRequestUrl ();
따라서 확장의 여지가 많이 있습니다. DB에서 동적으로로드 한 다음 URL의 구성을 판단 할 수 있습니다.
이 역할 기반 보터를 사용하는 방법은 무엇입니까? AccessDecisionManager 메소드를 사용하여 구성에서 사용자 정의하십시오. 우리는 공식 만장일 기반을 사용한 다음 맞춤형 역할 기반 보터를 추가해야합니다.
@enablewebsecurity @enableglobalmethodsecurity (prepostenabled = true, securedenabled = true) public class securityconfiguration websecurityConfigurerAdapter {@override protected void configure (httpsecurity http) 예외 {http .addfilterbefore, usernamepasswordauthenticationfilter.class) .exceptionHandling () .AuthenticationEntryPoint (문제점) .AccessDeniedHandler (refluesupport). () .csrf () .Disable () .frameOptions () .disable () .andsection -menagement (). . 및 () .authorizeRequests () // custom accessDecisionManager .accessDecisionManager (accessDecisionManager ()). } @Bean public accessDecisionManager accessDecisionManager () {list <accessDecisionVoTer <? 객체를 확장하십시오 >> dectionVoTers = arrays.AsList (new WebExpressionVoTer (), // new rolevoTer (), new RoleBasedVoTer (), new AuthEnticatedVoTer ()); 새로운 만장일 기반 (의사 결정자)을 반환합니다. }SecurityMetadatAsource를 사용자 정의하십시오
Custom FilterInvocationsecurityMetAdatAsource는 인터페이스 만 구현하면 인터페이스에서 DB에서 규칙을 동적으로로드하면됩니다.
코드의 정의를 재사용하기 위해 코드에서 생성 된 SecurityMetadatAsource를 가져 와서 생성자의 기본 FilterInvocationsecurityMetAdatAsource를 전달할 수 있습니다.
공개 클래스 AppFilterInvocationsecurityMetadatAsource는 org.springframework.security.web.access.intercept.filterinvocationsecuritymetadatasource {private filterinvocationsecuritymetAsource SuperMetAdatAsource; @override public Collection <configattribute> getAllConfigattributes () {return null; } public applterinvocationsecuritymetadataSource (filterInvocationsecurityMetAdatAsource 표현지 basedFilterInVocationSecurityMetAdAtAsource) {this.SuperMetAdatAsource = ExpressionBasedFilterInvocationSecutionMetAsource; // 데이터베이스에서 TODO로드 권한 구성} 개인 최종 AntPathMatcher AntPathMatcher = New AntpathMatcher (); // 여기에 개인 최종 맵 <string, String> urlRolemap = new Hashmap <String, String> () {{put ( "/open/**", "role_anonymous"); put ( "/health", "role_anonymous"); put ( "/다시 시작", "role_admin"); put ( "/demo", "role_user"); }}; @override public collection <configattribute> getAttributes (Object)는 불법 행위를 던졌습니다. {filterinvocation fi = (filterinvocation) 객체; 문자열 url = fi.getRequestUrl (); for (map.Entry <string, string> entry : urlRolemap.entryset ()) {if (antpathMatcher.match (enther.getKey (), url)) {return securityconfig.createList (endent.getValue ()); }} // 코드로 정의 된 기본 구성을 반환합니다. } @override public boolean supports (class <?> clazz) {return filterinvocation.class.isassignablefrom (Clazz); }}그것을 사용하는 방법? AccessDecisionManager와 달리 ExpressionUrlauthorizationConfigurer는 FilterSecurityInterceptor의 FilterInvocationsecurityMetAdatAsource를 설정하는 설정 방법을 제공하지 않습니다.
FiltersecurityInterceptor 유형을 처리하는 ObjectPostProcessor를 사용자 정의하는 ObjectPostProcessor를 사용하여 확장 메소드를 발견하면 FilterSecurityInterceptor를 수정할 수 있습니다.
@enablewebsecurity @enableglobalmethodsecurity (prepostenabled = true, securedenabled = true) public class securityconfiguration websecurityConfigurerAdapter {@override protected void configure (httpsecurity http) 예외 {http .addfilterbefore, usernamepasswordauthenticationfilter.class) .exceptionHandling () .AuthenticationEntryPoint (문제점) .AccessDeniedHandler (refluesupport). () .csrf () .Disable () .frameOptions () .disable () .andsection -menagement (). . 및 () .authorizeRequests () // custom filterInvocationsecurityMetAdatAsource .withObjectPostProcessor (new ObjectPostProcessor <FiltersecurityInterceptor> () {@override public <o psomprocess (o fsi) { fsi.setsecuritymetadatasource (mysecuritymetadatasource (fsi.getsecuritymetadatasource ()); } @Bean Public AppFilterInvocationsecutionMetAdatAsource MySecurityMetadatAsource (FilterInvocationsecurityMetAdatAsource FilterInvocationsecurityMetadAsource) {AppFilterInvocationsecutionAdatAsource SecurityMetAdatAsource = New AppFilterInvocationsecurityMetAdatAsource (FilterInvocationsecurityMetAdatAsource); 반품 SecurityMetadatAsource;}요약
이 기사는 스프링 보안을 기반으로 동적 권한을 구현하는 두 가지 방법을 소개합니다. 하나는 AccessDecisionManager를 사용자 정의하고 다른 하나는 FilterInvocationsecurityMetAdatAsource를 사용자 정의하는 것입니다. 실제 프로젝트의 요구에 따라 유연하게 선택할 수 있습니다.
추가 읽기 :
스프링 보안 아키텍처 및 소스 코드 분석
요약
위는이 기사의 전체 내용입니다. 이 기사의 내용에 모든 사람의 연구 나 작업에 대한 특정 참조 가치가 있기를 바랍니다. 궁금한 점이 있으면 의사 소통을 위해 메시지를 남길 수 있습니다. Wulin.com을 지원 해주셔서 감사합니다.