spring security 동적 설정 url 권한 의 2 가지 실현 방법
표준 RABC,권한 은 동적 설정 을 지원 해 야 합 니 다.spring security 는 기본적으로 코드 에 권한 을 약정 합 니 다.실제 업무 장면 은 동적 설정 캐릭터 접근 권한 을 지원 해 야 합 니 다.즉,실행 할 때 url 에 대응 하 는 방문 캐릭터 를 설정 해 야 합 니 다.
spring security 를 바탕 으로 이 수 요 를 어떻게 실현 합 니까?
가장 쉬 운 방법 은 필터 하 나 를 사용자 정의 하여 권한 판단 을 완성 하 는 것 입 니 다.그러나 이것 은 spring security 프레임 워 크 에서 벗 어 났 습 니 다.어떻게 spring security 를 바탕 으로 우아 하 게 실현 할 수 있 습 니까?
spring 보안 권한 부여 회고
spring security 는 FilterChainProxy 를 통 해 웹 에 등 록 된 filter 입 니 다.FilterChainProxy 에는 한 번 에 여러 개의 필터 가 포함 되 어 있 습 니 다.먼저 spring security 에 내 장 된 여러 filter 를 알 아야 합 니 다.
Alias
Filter Class
Namespace Element or Attribute
CHANNEL_FILTER
ChannelProcessingFilter
http/intercept-url@requires-channel
SECURITY_CONTEXT_FILTER
SecurityContextPersistenceFilter
http
CONCURRENT_SESSION_FILTER
ConcurrentSessionFilter
session-management/concurrency-control
HEADERS_FILTER
HeaderWriterFilter
http/headers
CSRF_FILTER
CsrfFilter
http/csrf
LOGOUT_FILTER
LogoutFilter
http/logout
X509_FILTER
X509AuthenticationFilter
http/x509
PRE_AUTH_FILTER
AbstractPreAuthenticatedProcessingFilter Subclasses
N/A
CAS_FILTER
CasAuthenticationFilter
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
REMEMBER_ME_FILTER
RememberMeAuthenticationFilter
http/remember-me
ANONYMOUS_FILTER
AnonymousAuthenticationFilter
http/anonymous
SESSION_MANAGEMENT_FILTER
SessionManagementFilter
session-management
EXCEPTION_TRANSLATION_FILTER
ExceptionTranslationFilter
http
FILTER_SECURITY_INTERCEPTOR
FilterSecurityInterceptor
http
SWITCH_USER_FILTER
SwitchUserFilter
N/A
가장 중요 한 것 은 FilterSecurity Interceptor 입 니 다.이 필 터 는 주요 인증 논 리 를 실 현 했 고 가장 핵심 적 인 코드 는 여기에 있 습 니 다.
protected InterceptorStatusToken beforeInvocation(Object object) {
// URL
Collection<ConfigAttribute> 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);
}
}
위 에서 보 듯 이 동태 감 권 을 실현 하려 면 두 가지 측면 에서 시작 할 수 있다.사용자 정의 AccessDecisionManager
공식 적 인 세 개의 AccessDecisionManager 는 모두 AccessDecisionVoter 를 바탕 으로 권한 인증 을 실현 하기 때문에 우 리 는 하나의 AccessDecisionVoter 만 사용자 정의 하면 된다.
사용자 정 의 는 주로 AccessDecisionVoter 인 터 페 이 스 를 실현 합 니 다.저 희 는 공식 RoleVoter 를 본 떠 서 하 나 를 실현 할 수 있 습 니 다.
public class RoleBasedVoter implements AccessDecisionVoter<Object> {
@Override
public boolean supports(ConfigAttribute attribute) {
return true;
}
@Override
public int vote(Authentication authentication, Object object, Collection<ConfigAttribute> attributes) {
if(authentication == null) {
return ACCESS_DENIED;
}
int result = ACCESS_ABSTAIN;
Collection<? extends GrantedAuthority> 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<? extends GrantedAuthority> extractAuthorities(
Authentication authentication) {
return authentication.getAuthorities();
}
@Override
public boolean supports(Class clazz) {
return true;
}
}
어떻게 동적 권한 에 가입 합 니까?vote(Authentication authentication, Object object, Collection<ConfigAttribute> attributes)
에 있 는 Object object 의 종 류 는 FilterInvocation 입 니 다.getRequestUrl 을 통 해 현재 요청 한 URL 을 가 져 올 수 있 습 니 다.
FilterInvocation fi = (FilterInvocation) object;
String url = fi.getRequestUrl();
따라서 DB 에서 동적 으로 불 러 온 다음 URL 의 ConfigAttribute 를 판단 하면 됩 니 다.이 RoleBasedVoter 를 어떻게 사용 합 니까?configure 에서 accessDecisionManager 방법 을 사용 하여 사용자 정의 합 니 다.저 희 는 공식 Unanimous Based 를 사용 한 다음 에 사용자 정의 Role Based Voter 를 가입 하면 됩 니 다.
@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<AccessDecisionVoter<? extends Object>> decisionVoters
= Arrays.asList(
new WebExpressionVoter(),
// new RoleVoter(),
new RoleBasedVoter(),
new AuthenticatedVoter());
return new UnanimousBased(decisionVoters);
}
사용자 정의 Security MetadataSource사용자 정의 FilterInvocation Security MetadataSource 는 인터페이스 만 실현 하면 되 며 인터페이스 에서 DB 동적 로드 규칙 을 사용 합 니 다.
코드 의 정 의 를 재 활용 하기 위해 서 는 코드 에 생 성 된 Security MetadataSource 테 이 프 를 구조 함수 에 기본 FilterInvocation Security MetadataSource 로 전송 할 수 있 습 니 다.
public class AppFilterInvocationSecurityMetadataSource implements org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource {
private FilterInvocationSecurityMetadataSource superMetadataSource;
@Override
public Collection<ConfigAttribute> getAllConfigAttributes() {
return null;
}
public AppFilterInvocationSecurityMetadataSource(FilterInvocationSecurityMetadataSource expressionBasedFilterInvocationSecurityMetadataSource){
this.superMetadataSource = expressionBasedFilterInvocationSecurityMetadataSource;
// TODO
}
private final AntPathMatcher antPathMatcher = new AntPathMatcher();
// DB
private final Map<String,String> urlRoleMap = new HashMap<String,String>(){{
put("/open/**","ROLE_ANONYMOUS");
put("/health","ROLE_ANONYMOUS");
put("/restart","ROLE_ADMIN");
put("/demo","ROLE_USER");
}};
@Override
public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
FilterInvocation fi = (FilterInvocation) object;
String url = fi.getRequestUrl();
for(Map.Entry<String,String> 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 와 달리 ExpressionUrl AuthorizationConfigurer 는 set 방법 으로 FilterSecurity Interceptor 의 FilterInvocation Security MetadataSource,how to do 를 설정 하지 않 았 습 니 다.확장 방법 withObject PostProcessor 를 발견 하면 이 방법 을 통 해 FilterSecurity Interceptor 형식 을 처리 하 는 Object PostProcessor 를 사용자 정의 하면 FilterSecurity Interceptor 를 수정 할 수 있 습 니 다.
@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<FilterSecurityInterceptor>() {
@Override
public <O extends FilterSecurityInterceptor> 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 를 바탕 으로 동적 권한 을 실현 하 는 두 가지 방법 을 소개 했다.하 나 는 accessDecisionManager 를 사용자 정의 하 는 것 이 고,다른 하 나 는 FilterInvocation Security MetadataSource 를 사용자 정의 하 는 것 이다.실제 항목 에 서 는 수요 에 따라 유연 하 게 선택 할 수 있다.
확장 읽 기:
Spring Security 구조 와 소스 코드 분석
총결산
이상 은 이 글 의 전체 내용 입 니 다.본 논문 의 내용 이 여러분 의 학습 이나 업무 에 어느 정도 참고 학습 가치 가 있 기 를 바 랍 니 다.궁금 한 점 이 있 으 시 면 댓 글 을 남 겨 주 셔 서 저희 에 대한 지지 에 감 사 드 립 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
thymeleaf로 HTML 페이지를 동적으로 만듭니다 (spring + gradle)지난번에는 에서 화면에 HTML을 표시했습니다. 이번에는 화면을 동적으로 움직여보고 싶기 때문에 입력한 문자를 화면에 표시시키고 싶습니다. 초보자의 비망록이므로 이상한 점 등 있으면 지적 받을 수 있으면 기쁩니다! ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.