Comment puis-je ajouter une sécurité basée sur une méthode à un projet de démarrage à ressort?

je veux ajouter la sécurité basée sur la méthode à un projet de démarrage à ressort.

il me semblait que tout ce dont j'avais besoin était d'ajouter PermissionEvaluator et MethodSecurityExpressionHandler haricots, annoter mon WebSecurityConfigurerAdapter avec @EnableGlobalMethodSecurity(prePostEnabled = true) et la méthode avec @PreAuthorize("isAuthenticated() and hasPermission(#param, 'somePermissionName')") .

mais après l'ajout d'un PermissionEvaluator bean

@Bean
public PermissionEvaluator permissionEvaluator() {
    HelloPermissionEvaluator bean = new HelloPermissionEvaluator();
    return bean;
}

j'obtiens une IllegalArgumentException : "Un ServletContext est requis pour la configuration par défaut de servlet de manutention":

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.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(<generated>)
    at org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration$$EnhancerBySpringCGLIB$$d7f296e3$$FastClassBySpringCGLIB$c20692.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

Tout ce que j'ai pu trouver sur le web est lié à jUnit testing. Pourquoi cette exception est-elle jetée? Ce qui me manque? Dois-je ajouter une fève ServletContext, et si oui, comment?

mes exigences sont Gradle, Spring Boot et java config (au lieu de XML config). La source minimale et complète est la suivante:


de l'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;
    }

}
"1519140920 de construire".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'
}
17
demandé sur Yurim 2014-05-13 22:01:36

2 réponses

essayez de mettre le PermissionEvaluator dans une classe séparée @Configuration . Vous semblez le forcer à être instancié avant que le ServletContext ne soit prêt (les filtres de sécurité du ressort doivent être créés très tôt pour que cela puisse se produire).

31
répondu Dave Syer 2014-05-14 06:28:42

a rencontré un problème similaire. Si vous voulez configurer custom permission evaluator dans expression handler, vous pouvez faire quelque chose comme ceci

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

}

si vous voulez utiliser explicitement Permission evaluator alors avec ce qui précède faites comme suggéré par Dave ie définissez permission evaluator bean dans son fichier de configuration.

0
répondu Anil Punia 2017-10-07 10:27:09