Comment configurer Spring Security pour permettre l'accès à l'URL Swagger sans authentification

92

Mon projet a Spring Security. Problème principal: impossible d'accéder à l'URL swagger à http: // localhost: 8080 / api / v2 / api-docs . Il indique l'en-tête d'autorisation manquant ou non valide.

Capture d'écran de la fenêtre du navigateur Mon pom.xml contient les entrées suivantes

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.4.0</version>
</dependency>

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.4.0</version>
</dependency>

SwaggerConfig:

@Configuration
@EnableSwagger2
public class SwaggerConfig {

@Bean
public Docket api() {
    return new Docket(DocumentationType.SWAGGER_2).select()
            .apis(RequestHandlerSelectors.any())
            .paths(PathSelectors.any())
            .build()
            .apiInfo(apiInfo());
}

private ApiInfo apiInfo() {
    ApiInfo apiInfo = new ApiInfo("My REST API", "Some custom description of API.", "API TOS", "Terms of service", "[email protected]", "License of API", "API license URL");
    return apiInfo;
}

AppConfig:

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = { "com.musigma.esp2" })
@Import(SwaggerConfig.class)
public class AppConfig extends WebMvcConfigurerAdapter {

// ========= Overrides ===========

@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(new LocaleChangeInterceptor());
}

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("swagger-ui.html")
      .addResourceLocations("classpath:/META-INF/resources/");

    registry.addResourceHandler("/webjars/**")
      .addResourceLocations("classpath:/META-INF/resources/webjars/");
}

Entrées web.xml:

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
        com.musigma.esp2.configuration.AppConfig
        com.musigma.esp2.configuration.WebSecurityConfiguration
        com.musigma.esp2.configuration.PersistenceConfig
        com.musigma.esp2.configuration.ACLConfig
        com.musigma.esp2.configuration.SwaggerConfig
    </param-value>
</context-param>

WebSecurityConfig:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@ComponentScan(basePackages = { "com.musigma.esp2.service", "com.musigma.esp2.security" })
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity
        .csrf()
            .disable()
        .exceptionHandling()
            .authenticationEntryPoint(this.unauthorizedHandler)
            .and()
        .sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
        .authorizeRequests()
            .antMatchers("/auth/login", "/auth/logout").permitAll()
            .antMatchers("/api/**").authenticated()
            .anyRequest().authenticated();

        // custom JSON based authentication by POST of {"username":"<name>","password":"<password>"} which sets the token header upon authentication
        httpSecurity.addFilterBefore(loginFilter(), UsernamePasswordAuthenticationFilter.class);

        // custom Token based authentication based on the header previously given to the client
        httpSecurity.addFilterBefore(new StatelessTokenAuthenticationFilter(tokenAuthenticationService), UsernamePasswordAuthenticationFilter.class);
    }
}
shubhendu_shekhar
la source

Réponses:

176

L'ajout de ceci à votre classe WebSecurityConfiguration devrait faire l'affaire.

@Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/v2/api-docs",
                                   "/configuration/ui",
                                   "/swagger-resources/**",
                                   "/configuration/security",
                                   "/swagger-ui.html",
                                   "/webjars/**");
    }

}
Stijn Maller
la source
11
Si vous utilisez swagger-ui, vous avez besoin de quelque chose comme ceci: .antMatchers ("/ v2 / api-docs", "/ configuration / ui", "/ swagger-resources", "/ configuration / security", "/ swagger-ui .html "," / webjars / ** "," / swagger-resources / configuration / ui "," / swagger-ui.html "). permitAll ()
Daniel Martín
2
Dans mon cas, cette règle fonctionne: .antMatchers ("/ v2 / api-docs", "/ configuration / ui", "/ swagger-resources", "/ configuration / security", "/swagger-ui.html", "/ webjars / **", "/ swagger-resources / configuration / ui", "/ swagge‌ r-ui.html", "/ swagger-resources / configuration / security"). permitAll ()
nikolai.serdiuk
6
Besoin de plus de règles: .antMatchers ("/", "/ csrf", "/ v2 / api-docs", "/ swagger-resources / configuration / ui", "/ configuration / ui", "/ swagger-resources", "/ swagger-resources / configuration / security", "/ configuration / security", "/swagger-ui.html", "/ webjars / **"). permitAll ()
Mate Šimović
5
Merci d'avoir répondu! Existe-t-il un risque de sécurité permettant d'accéder aux webjars / **?
ssimm
réponse très utile
Praveenkumar Beedanal
26

J'ai mis à jour avec / configuration / ** et / swagger-resources / ** et cela a fonctionné pour moi.

@Override
public void configure(WebSecurity web) throws Exception {
    web.ignoring().antMatchers("/v2/api-docs", "/configuration/ui", "/swagger-resources/**", "/configuration/**", "/swagger-ui.html", "/webjars/**");

}
Akshata Suvarna
la source
Parfait! Résolu le problème.
Madhu
24

J'ai eu le même problème avec Spring Boot 2.0.0.M7 + Spring Security + Springfox 2.8.0. Et j'ai résolu le problème en utilisant la configuration de sécurité suivante qui permet l'accès public aux ressources de l'interface utilisateur de Swagger.

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    private static final String[] AUTH_WHITELIST = {
            // -- swagger ui
            "/v2/api-docs",
            "/swagger-resources",
            "/swagger-resources/**",
            "/configuration/ui",
            "/configuration/security",
            "/swagger-ui.html",
            "/webjars/**"
            // other public endpoints of your API may be appended to this array
    };


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.
                // ... here goes your custom security configuration
                authorizeRequests().
                antMatchers(AUTH_WHITELIST).permitAll().  // whitelist Swagger UI resources
                // ... here goes your custom security configuration
                antMatchers("/**").authenticated();  // require authentication for any endpoint that's not whitelisted
    }

}
naXa
la source
2
après avoir ajouté cette classe, je suis capable de voir swagger-ui mais les API ne sont pas accessibles via postman même avec access_token, obtenant une erreur d'accès interdit comme ci-dessous,{ "timestamp": 1519798917075, "status": 403, "error": "Forbidden", "message": "Access Denied", "path": "/<some path>/shop" }
Chandrakant Audhutwar
@ChandrakantAudhutwar delete antMatchers("/**").authenticated()instruction ou remplacez-la par votre propre configuration d'authentification. Soyez prudent, vous savez mieux ce que vous faites avec la sécurité.
naXa
oui, cela a fonctionné. Je ne pensais qu'à contourner swagger-ui, mais d'autres API car il est sécurisé. maintenant mes API sont également contournées.
Chandrakant Audhutwar
@ChandrakantAudhutwar vous n'avez pas besoin de copier-coller toute la SecurityConfigurationclasse dans votre projet. Vous devez avoir le vôtre SecurityConfigurationoù vous autorisez les requêtes aux ressources de l'interface utilisateur Swagger et gardez vos API sécurisées.
naXa
J'ai AuthorizationServerConfigurerAdapterimplémenté une classe qui rend l'authentification de l'API.
Chandrakant Audhutwar
12

Pour ceux qui utilisent une version plus récente de Swagger 3 org.springdoc:springdoc-openapi-ui

@Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/v3/api-docs/**", "/swagger-ui.html", "/swagger-ui/**");
    }
}
Dennis Glot
la source
1
Remarque: Si cela vous empêche d'obtenir une erreur "Authentification requise", mais vous montre simplement une page vierge, j'ai également dû ajouter "/ swagger-resources / **" et "/ swagger-resources" dans cette liste et cela a été corrigé ça pour moi.
Vinícius M le
5

si votre version springfox supérieure à 2.5 , doit être ajoutée à WebSecurityConfiguration comme ci-dessous:

@Override
public void configure(HttpSecurity http) throws Exception {
    // TODO Auto-generated method stub
    http.authorizeRequests()
        .antMatchers("/v2/api-docs", "/swagger-resources/configuration/ui", "/swagger-resources", "/swagger-resources/configuration/security", "/swagger-ui.html", "/webjars/**").permitAll()
        .and()
        .authorizeRequests()
        .anyRequest()
        .authenticated()
        .and()
        .csrf().disable();
}
duliu1990
la source
duliu1990 a raison, depuis springfox 2.5+, toutes les ressources springfox (swagger inclus) ont été déplacées sous /swagger-resources. /v2/api-docsest le point de terminaison par défaut de l'API swagger (sans souci avec l'interface utilisateur), qui peut être remplacé par la variable de configuration springfox.documentation.swagger.v2.path springfox
Mahieddine M. Ichir
3

Plus ou moins cette page a des réponses mais toutes ne sont pas au même endroit. J'étais confronté au même problème et j'y ai passé un bon moment. Maintenant, j'ai une meilleure compréhension et je voudrais la partager ici:

I Activation de l'interface utilisateur Swagger avec Spring Websecurity:

Si vous avez activé Spring Websecurity par défaut, il bloquera toutes les requêtes adressées à votre application et retournera 401. Cependant, pour que l'interface utilisateur swagger se charge dans le navigateur, swagger-ui.html effectue plusieurs appels pour collecter des données. La meilleure façon de déboguer est d'ouvrir swagger-ui.html dans un navigateur (comme google chrome) et d'utiliser les options de développement (touche 'F12'). Vous pouvez voir plusieurs appels effectués lorsque la page se charge et si le swagger-ui ne se charge pas complètement, il est probable que certains d'entre eux échouent.

vous devrez peut-être dire à Spring Websecurity d'ignorer l'authentification pour plusieurs modèles de chemin swagger. J'utilise swagger-ui 2.9.2 et dans mon cas ci-dessous sont les modèles que j'ai dû ignorer:

Cependant, si vous utilisez une version différente, la vôtre peut changer. vous devrez peut-être trouver le vôtre avec l'option développeur dans votre navigateur, comme je l'ai déjà dit.

@Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
public void configure(WebSecurity web) throws Exception {
    web.ignoring().antMatchers("/v2/api-docs", "/configuration/ui", 
            "/swagger-resources/**", "/configuration/**", "/swagger-ui.html"
            , "/webjars/**", "/csrf", "/");
}
}

II Activation de l'interface utilisateur swagger avec l'intercepteur

En général, vous ne voudrez peut-être pas intercepter les requêtes effectuées par swagger-ui.html. Pour exclure plusieurs modèles de swagger ci-dessous est le code:

La plupart des modèles de cas pour la sécurité Web et l'intercepteur seront les mêmes.

@Configuration
@EnableWebMvc
public class RetrieveCiamInterceptorConfiguration implements WebMvcConfigurer {

@Autowired
RetrieveInterceptor validationInterceptor;

@Override
public void addInterceptors(InterceptorRegistry registry) {

    registry.addInterceptor(validationInterceptor).addPathPatterns("/**")
    .excludePathPatterns("/v2/api-docs", "/configuration/ui", 
            "/swagger-resources/**", "/configuration/**", "/swagger-ui.html"
            , "/webjars/**", "/csrf", "/");
}

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("swagger-ui.html")
      .addResourceLocations("classpath:/META-INF/resources/");

    registry.addResourceHandler("/webjars/**")
      .addResourceLocations("classpath:/META-INF/resources/webjars/");
}

}

Comme vous devrez peut-être activer @EnableWebMvc pour ajouter des intercepteurs, vous devrez peut-être également ajouter des gestionnaires de ressources à swagger, comme je l'ai fait dans l'extrait de code ci-dessus.

chanderdevx
la source
Pourquoi ajoutez-vous l' /csrfexclusion?
Vishal le
2

Limitation uniquement aux ressources liées à Swagger:

.antMatchers("/v2/api-docs", "/swagger-resources/**", "/swagger-ui.html", "/webjars/springfox-swagger-ui/**");
m52509791
la source
2

Voici une solution complète pour Swagger avec Spring Security . Nous souhaitons probablement activer Swagger uniquement dans notre environnement de développement et d'assurance qualité et le désactiver dans l'environnement de production. Donc, j'utilise une propriété ( prop.swagger.enabled) comme indicateur pour contourner l'authentification de sécurité Spring pour swagger-ui uniquement dans l'environnement de développement / qa.

@Configuration
@EnableSwagger2
public class SwaggerConfiguration extends WebSecurityConfigurerAdapter implements WebMvcConfigurer {

@Value("${prop.swagger.enabled:false}")
private boolean enableSwagger;

@Bean
public Docket SwaggerConfig() {
    return new Docket(DocumentationType.SWAGGER_2)
            .enable(enableSwagger)
            .select()
            .apis(RequestHandlerSelectors.basePackage("com.your.controller"))
            .paths(PathSelectors.any())
            .build();
}

@Override
public void configure(WebSecurity web) throws Exception {
    if (enableSwagger)  
        web.ignoring().antMatchers("/v2/api-docs",
                               "/configuration/ui",
                               "/swagger-resources/**",
                               "/configuration/security",
                               "/swagger-ui.html",
                               "/webjars/**");
}

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    if (enableSwagger) {
        registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
    }
  }
}
Abdul Rahman
la source
1

J'utilise Spring Boot 5. J'ai ce contrôleur que je veux qu'un utilisateur non authentifié appelle.

  //Builds a form to send to devices   
@RequestMapping(value = "/{id}/ViewFormit", method = RequestMethod.GET)
@ResponseBody
String doFormIT(@PathVariable String id) {
    try
    {
        //Get a list of forms applicable to the current user
        FormService parent = new FormService();

Voici ce que j'ai fait dans la configuration.

  @Override
   protected void configure(HttpSecurity http) throws Exception {
    http
            .authorizeRequests()
            .antMatchers(
                    "/registration**",
                    "/{^[\\\\d]$}/ViewFormit",

J'espère que cela t'aides....

smac2020
la source
0

Compte tenu de toutes vos demandes d'API situées avec un modèle d'URL, /api/..vous pouvez dire à spring de ne sécuriser que ce modèle d'URL en utilisant la configuration ci-dessous. Ce qui signifie que vous dites à Spring ce qu'il faut sécuriser au lieu de ce qu'il faut ignorer.

@Override
protected void configure(HttpSecurity http) throws Exception {
  http
    .csrf().disable()
     .authorizeRequests()
      .antMatchers("/api/**").authenticated()
      .anyRequest().permitAll()
      .and()
    .httpBasic().and()
    .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
Siddu
la source
1
Merci pour cet extrait de code, qui pourrait fournir une aide limitée à court terme. Une explication appropriée améliorerait considérablement sa valeur à long terme en montrant pourquoi c'est une bonne solution au problème, et la rendrait plus utile aux futurs lecteurs avec d'autres questions similaires. Veuillez modifier votre réponse pour ajouter des explications, y compris les hypothèses que vous avez formulées.
Toby Speight