[SPRING] 스프링 부트 프로젝트에 메소드 기반 보안을 어떻게 추가합니까?
SPRING스프링 부트 프로젝트에 메소드 기반 보안을 어떻게 추가합니까?
스프링 부트 프로젝트에 메소드 기반 보안을 추가하고 싶다.
PermissionEvaluator 및 MethodSecurityExpressionHandler 빈을 추가하고 @EnableGlobalMethodSecurity (prePostEnabled = true) 및 @PreAuthorize ( "isAuthenticated () 및 hasPermission (#param, 'somePermissionName')") 메소드에 주석을 달아 주면됩니다.
그러나 PermissionEvaluator 빈을 추가 한 후에
@Bean
public PermissionEvaluator permissionEvaluator() {
HelloPermissionEvaluator bean = new HelloPermissionEvaluator();
return bean;
}
IllegalArgumentException가 발생합니다 : "ServletContext는 기본 서블릿 처리를 구성하는 데 필요합니다"
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'defaultServletHandlerMapping' defined in class path resource [org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfiguration.class]: Instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public org.springframework.web.servlet.HandlerMapping org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport.defaultServletHandlerMapping()] threw exception; nested exception is java.lang.IllegalArgumentException: A ServletContext is required to configure default servlet handling
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:597)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1094)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:989)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:504)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:304)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:300)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:703)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:760)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:120)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:648)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:311)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:909)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:898)
at com.domain.simple.Application.main(Application.java:14)
Caused by: org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public org.springframework.web.servlet.HandlerMapping org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport.defaultServletHandlerMapping()] threw exception; nested exception is java.lang.IllegalArgumentException: A ServletContext is required to configure default servlet handling
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:188)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:586)
... 17 more
Caused by: java.lang.IllegalArgumentException: A ServletContext is required to configure default servlet handling
at org.springframework.util.Assert.notNull(Assert.java:112)
at org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer.<init>(DefaultServletHandlerConfigurer.java:54)
at org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport.defaultServletHandlerMapping(WebMvcConfigurationSupport.java:346)
at org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration$$EnhancerBySpringCGLIB$$d7f296e3.CGLIB$defaultServletHandlerMapping$26(<generated>)
at org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration$$EnhancerBySpringCGLIB$$d7f296e3$$FastClassBySpringCGLIB$$48c20692.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:312)
at org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration$$EnhancerBySpringCGLIB$$d7f296e3.defaultServletHandlerMapping(<generated>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:166)
... 18 more
웹에서 찾을 수있는 것은 jUnit 테스트와 관련이 있습니다. 왜이 예외가 던져 집니까? 내가 뭘 놓치고 있니? ServletContext 빈을 추가해야합니까? 그렇다면 어떻게해야합니까?
내 요구 사항은 Gradle, Spring Boot 및 java config (XML 구성 대신)입니다. 최소한의 완전한 소스는 다음과 같습니다.
Application.java
package com.domain.simple;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@EnableAutoConfiguration
@Configuration
@ComponentScan
public class Application {
public static void main(String[] args) throws Throwable {
SpringApplication.run(Application.class, args);
}
}
HelloController.java
package com.domain.simple;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class HelloController {
Logger log = LoggerFactory.getLogger(HelloController.class);
// @PreAuthorize("isAuthenticated() and hasPermission(#param, 'somePermissionName')")
@RequestMapping(value = "/hello/{param}")
@ResponseBody
public String hello(@PathVariable("param") String param) {
log.info("hello(" + param + ") called");
return "Hello " + param;
}
}
HelloPermissionEvaluator.java
package com.domain.simple;
import java.io.Serializable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.core.Authentication;
public class HelloPermissionEvaluator implements PermissionEvaluator {
Logger log = LoggerFactory.getLogger(HelloPermissionEvaluator.class);
@Override
public boolean hasPermission(Authentication authentication,
Object targetDomainObject, Object permission) {
log.info("hasPermission(Authentication, Object, Object) called");
return true;
}
@Override
public boolean hasPermission(Authentication authentication,
Serializable targetId, String targetType, Object permission) {
log.error("hasPermission(Authentication, Serializable, String, Object) called");
throw new RuntimeException("ID based permission evaluation currently not supported.");
}
}
WebSecurityConfig.java
package com.domain.simple;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
@ComponentScan
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder authManagerBuilder)
throws Exception {
authManagerBuilder.inMemoryAuthentication().withUser("user")
.password("password").roles("USER");
}
// @Bean
// public MethodSecurityExpressionHandler expressionHandler() {
// DefaultMethodSecurityExpressionHandler bean = new DefaultMethodSecurityExpressionHandler();
// bean.setPermissionEvaluator(permissionEvaluator());
// return bean;
// }
// this causes an IllegalArgumentException ("A ServletContext is required to configure default servlet handling")
@Bean
public PermissionEvaluator permissionEvaluator() {
HelloPermissionEvaluator bean = new HelloPermissionEvaluator();
return bean;
}
}
build.gradle
buildscript {
repositories {
maven { url "http://repo.spring.io/libs-snapshot" }
mavenLocal()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.0.2.RELEASE")
}
}
apply plugin: 'eclipse'
apply plugin: 'java'
apply plugin: 'spring-boot'
jar {
baseName = 'simple'
version = '0.1.0'
}
repositories {
mavenCentral()
maven { url "http://repo.spring.io/libs-snapshot" }
}
dependencies {
compile("org.springframework.boot:spring-boot-starter-web")
compile("org.springframework.boot:spring-boot-starter-security")
}
task wrapper(type: Wrapper) {
gradleVersion = '1.12'
}
해결법
-
==============================
1.PermissionEvaluator를 별도의 @Configuration 클래스에 두어보십시오. ServletContext가 준비되기 전에 강제로 인스턴스화 된 것처럼 보입니다 (스프링 보안 필터는 초 일찍 만들어 져야만합니다).
PermissionEvaluator를 별도의 @Configuration 클래스에 두어보십시오. ServletContext가 준비되기 전에 강제로 인스턴스화 된 것처럼 보입니다 (스프링 보안 필터는 초 일찍 만들어 져야만합니다).
-
==============================
2.비슷한 문제가 생겼다. 식 처리기에서 사용자 지정 권한 평가기를 구성하려면 다음과 같이 할 수 있습니다
비슷한 문제가 생겼다. 식 처리기에서 사용자 지정 권한 평가기를 구성하려면 다음과 같이 할 수 있습니다
public class SecurityPermissionEvaluator implements PermissionEvaluator { //A is a spring managed bean on which permission evaluator depends private A a; @Autowired public SecurityPermissionEvaluator(A a){ this.a = a; } @Override public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) { return false; } } then @Configuration @EnableGlobalMethodSecurity(prePostEnabled = true) public class WebSecurityConfiguration extends GlobalMethodSecurityConfiguration { @Autowired private A a; @Override protected MethodSecurityExpressionHandler createExpressionHandler() { DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler(); PermissionEvaluator permissionEvaluator = new SecurityPermissionEvaluator(a); expressionHandler.setPermissionEvaluator(permissionEvaluator); return expressionHandler; } }
위와 같이 명시 적으로 권한 평가기를 사용하려면 Dave가 제안한대로 (즉, 설정 파일에 권한 평가 기 Bean을 정의하십시오).
from https://stackoverflow.com/questions/23638462/how-do-i-add-method-based-security-to-a-spring-boot-project by cc-by-sa and MIT license
'SPRING' 카테고리의 다른 글
[SPRING] 스프링 부트의 기본 스케줄러 풀 크기는 얼마입니까? (0) | 2019.01.02 |
---|---|
[SPRING] jsp의 세션 속성 인쇄 (0) | 2019.01.02 |
[SPRING] Spring JpaRepository - 엔티티 분리 및 연결 (0) | 2019.01.02 |
[SPRING] Spring 데이터 JPA : query ManyToMany (0) | 2019.01.02 |
[SPRING] Spring RestTemplate을 사용하여 페이지 <Entity> 응답을 소비하는 방법 (0) | 2019.01.02 |