web-dev-qa-db-fra.com

Spring Security, l'annotation Method Security (@Secured) ne fonctionne pas (config Java)

J'essaie de configurer une annotation de sécurité de méthode à l'aide de @Secured ("ADMIN") (sans XML, uniquement la configuration Java, Spring Boot). Mais l'accès via les rôles ne fonctionne pas.

Configuration de sécurité:

@Configuration
@EnableWebSecurity
public class AppSecurityConfiguration extends WebSecurityConfigurerAdapter{

.....

@Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatchers("/api/**").fullyAuthenticated().and()
                .addFilterBefore(tokenAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
    }

.....

}

Je veux restreindre l'accès à la méthode du contrôleur:

@RestController
@RequestMapping("/api/groups")
public class GroupController {

    @Autowired
    private GroupService groupService;

    @Secured("ADMIN")
    @RequestMapping
    public List<Group> list() {
        return groupService.findAll();
    }

}

Restreindre l'accès par l'URL fonctionne, avec:

.antMatchers("/api/**").hasAuthority("ADMIN")

Peut-être que j'ai oublié de spécifier que je veux restreindre par les rôles?

UPD: Selon les règles, sur quelle couche doit être @PreAuthorize("hasRole('ADMIN')") dans la couche contrôleur ou dans la couche service?

13
silverhawk

Ce problème a été résolu.

J'ajoute @EnableGlobalMethodSecurity(prePostEnabled = true)

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class AppSecurityConfiguration extends WebSecurityConfigurerAdapter{
}

Et dans le contrôleur, j'ai changé @Secured("ADMIN") en @PreAuthorize("hasRole('ADMIN')")

1
silverhawk

Veuillez ajouter ceci 

@EnableGlobalMethodSecurity(securedEnabled = true)

Cet élément est utilisé pour activer la sécurité basée sur les annotations dans votre application (en définissant les attributs appropriés), ainsi que pour regrouper les déclarations de coupure de sécurité qui seront appliquées à l'ensemble du contexte de votre application, spécifiquement pour @Secured. le code devrait ressembler à ceci

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
public class AppSecurityConfiguration extends WebSecurityConfigurerAdapter{..
24
Mudassar

Il peut y avoir de nombreuses raisons pour lesquelles la sécurité de méthode sur un contrôleur ne fonctionne pas.

D'abord parce que ce n'est jamais cité en exemple dans le manuel Spring Security ... plaisanter mais il peut être difficile de prendre des outils Spring où ils ne veulent pas aller.

Plus sérieusement, vous devriez activer la sécurité des méthodes, comme l'a déjà dit @Mudassar. Le manuel dit:

Nous pouvons activer la sécurité basée sur les annotations à l'aide de l'annotation @EnableGlobalMethodSecurity sur n'importe quelle instance @Configuration. Par exemple, les éléments suivants activeraient l’annotation @Secured de Spring Security.

@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true)
public class MethodSecurityConfig {
   // ...
}

Notez que la réponse de Mudassar est correcte jusque là.

Mais la sécurité des méthodes est basée sur AOP, qui utilise par défaut le proxy JDK sur interfaces . C'est la raison pour laquelle tous les exemples appliquent la sécurité de méthode sur la couche service, car les classes de service sont normalement injectées dans les contrôleurs en tant qu'interfaces.

Vous pouvez bien sûr l’utiliser sur la couche contrôleur, mais:

  • soit tous vos contrôleurs implémentent des interfaces pour vous toutes les méthodes annotées @Secured
  • ou vous devez passer en classe proxy

La règle que j'essaie de suivre est la suivante:

  • si je veux sécuriser une URL, je m'en tiens à HTTPSecurity
  • si je dois autoriser un accès plus fin, j'ajoute la sécurité au niveau de la couche service
12
Serge Ballesta

Je sais que ce fil est assez ancien et ma réponse fait allusion à des parties des réponses de différentes personnes dans ce fil; mais voici une liste combinée de pièges et de réponses:

  1. Lors de l’utilisation de @Secured, le nom du rôle est (par exemple) ADMIN; cela signifie une annotation de @Secured ("ROLE_ADMIN").
  2. WebSecurityConfigurerAdapter doit avoir @EnableGlobalMethodSecurity (securedEnabled = true)
  3. Comme avec la plupart des serveurs proxy liés à Spring, assurez-vous que la classe et les méthodes sécurisées ne sont en aucun cas définitives. Pour Kotlin, cela signifie "ouvrir" chaque méthode ainsi que la classe.
  4. Lorsque la classe et ses méthodes sont virtuelles ("open"), aucune interface n’est implicitement nécessaire.

Voici une partie d'un exemple de travail Kotlin:

@RestController
@RequestMapping("api/v1")

    open class DiagnosticsController {
        @Autowired
        lateinit var systemDao : SystemDao

        @RequestMapping("ping", method = arrayOf(RequestMethod.GET))
        @Secured("ROLE_ADMIN")
        open fun ping(request : HttpServletRequest, response: HttpServletResponse) : String { ... 
    }

et

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
open class WebSecurityConfig : WebSecurityConfigurerAdapter() {

Cordialement

8
user1210708

Vous devez utiliser @secured (ROLE_ADMIN) au lieu de @secured (ADMIN). Vous devez écrire "ROLE_" avant de votre nom de rôle. Veuillez trouver l'exemple mentionné ci-dessous, qui s'assure que seul un utilisateur avec un rôle Admin peut accéder à la méthode list ().

@RestController
@RequestMapping("/api/groups")
public class GroupController {

    @Autowired
    private GroupService groupService;

    @Secured("ROLE_ADMIN")
    @RequestMapping
    public List<Group> list() {
        return groupService.findAll();
    }

}
1
Sadiq Ali

Je veux partager ma décision, peut-être que cela sera utile.

Used spring mvc + spring security , version 4.2.9.RELEASE

Par exemple, j'ai un service avec la méthode annotée @Secured 

@Secured("ACTION_USER_LIST_VIEW")
List<User> getUsersList();

Mais cela n'a pas fonctionné, car GlobalMethodSecurityConfiguration possède une méthode interne.

protected AccessDecisionManager accessDecisionManager()

dans lequel initialisé new RoleVoter() avec rolePrefix = "ROLE_"; par défaut (il est impossible d'utiliser des beans pour définir votre rolePrefix)} qui nous donne des annotations inopérantes, car RoleVoter attend une valeur d'annotation commençant par ROLE_ '

Pour résoudre ce problème, je remplace GlobalMethodSecurityConfiguration like this

@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true)
public class AppMethodSecurityConfiguration extends GlobalMethodSecurityConfiguration {
    @Override
    protected AccessDecisionManager accessDecisionManager() {
        List<AccessDecisionVoter<? extends Object>> decisionVoters = new ArrayList<>();
        ExpressionBasedPreInvocationAdvice expressionAdvice = new ExpressionBasedPreInvocationAdvice();
        expressionAdvice.setExpressionHandler(getExpressionHandler());
        decisionVoters.add(getRoleVoter());
        decisionVoters.add(new AuthenticatedVoter());
        return new AffirmativeBased(decisionVoters);
    }

    private RoleVoter getRoleVoter() {
        RoleVoter e = new RoleVoter();
        e.setRolePrefix("");
        return e;
    }
}
0
Igor

Vous devriez peut-être enregistrer votre AppSecurityConfiguration dans le même contexte que WebMvcConfig (qui étend WebMvcConfigurerAdapter).

AnnotationConfigWebApplicationContext mvcContext = new AnnotationConfigWebApplicationContext();      
mvcContext.register(WebMvcConfig.class, SecurityConfig.class);
0
digz6666