web-dev-qa-db-fra.com

Spring Boot2 Oauth2 Implicit Flow - http: // localhost: 8080/oauth/authorise à obtenir un accès refusé

J'ai créé une application Spring Boot 2, intégrée à SpringFox Swagger 2.8.0 avec une autorisation implicite Oauth2 pour l'authentification et l'autorisation.

Le code fonctionne bien, mais lorsque je clique sur le bouton Autoriser, il est redirigé vers le 

http: // localhost: 8080/oauth/authorize? response_type = token & client_id = test-app-client-id & redirect_uri = http% 3A% 2F% 2Flocalhost% 3A8080% 2Fwebjars% 2Fspringfox-swagger-ui% 2Foauth2-redirect.html read & state = U3VuIE9jdCAxNCAyMDE4IDIwOjQyOjUwIEdNVCswNTMwIChJbmRpYSBTdGFuZGFyZCBUaW1lKQ% 3D% 3D

mais montre Access Denied comme ci-dessous. 

Mon projet complet est disponible dans GitHub

MainApplication.Java

@EnableSwagger2
@SpringBootApplication
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
@RestController
public class MainApplication /*extends WebMvcConfigurerAdapter*/
{

    public static void main(String[] args)
    {
        SpringApplication.run(MainApplication.class, args);
    }

    @RequestMapping("/user")
    public Principal user(Principal user) {
        return user;
    }

    @Bean
    SecurityConfiguration security() {
      return SecurityConfigurationBuilder.builder()//<19>
          .clientId("test-app-client-id")
          .build();
    }

    @Bean
    SecurityScheme oauth() {
          List<GrantType> grantTypes = new ArrayList<>();
          ImplicitGrant implicitGrant = new ImplicitGrant(new LoginEndpoint("http://localhost:8080/oauth/authorize"),"access_code");
          grantTypes.add(implicitGrant);
          List<AuthorizationScope> scopes = new ArrayList<>();
          scopes.add(new AuthorizationScope("read","Read access on the API"));
        return new OAuthBuilder()
                .name("SECURITY_SCHEME_OAUTH2")
                .grantTypes(grantTypes)
                .scopes(scopes)
                .build();
    }

    @Bean
    public Docket docket()
    {
        return new Docket(DocumentationType.SWAGGER_2)
            .select()
            .apis(RequestHandlerSelectors.basePackage(getClass().getPackage().getName()))
            .paths(PathSelectors.any())
            .build()
            .securitySchemes(Collections.singletonList(oauth()))
            .apiInfo(generateApiInfo());
    }


    private ApiInfo generateApiInfo()
    {
        return new ApiInfo("Sample Service", "This service is to check Sample Service.", "Version 1.0",
            "Sample Service", "[email protected]", "Apache 2.0", "http://www.Apache.org/licenses/LICENSE-2.0");
    }
}

 enter image description here

Mise à jour 1

J'ai ajouté la sécurité et le mot de passe configure préconisés par @AlexanderPetrov. Les choses fonctionnent bien, lorsque j'ajoute @EnableResourceServer, mon écran de connexion indique une authentification complète est requise pour accéder à cette ressource comme illustré ci-dessous.

 enter image description here

Quelqu'un peut-il m'aider s'il vous plaît sur ce

7
Alex Man

Vous devez faire les changements suivants dans votre code

  1. La configuration de connexion de formulaire est nécessaire pour le flux implicite. 
  2. De plus, si nous utilisons un jeton de flux implicite, il sera généré par l'URL d'autorisation au lieu d'URL de jeton. Vous devez donc remplacer "/ oauth/token" par "oauth/authorize". configurer la méthode ci-dessous 

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers("/oauth/authorize").authenticated()
        .and()
        .authorizeRequests().anyRequest().permitAll()
        .and()
        .formLogin().permitAll()
        .and()
        .csrf().disable();
    }
    
  3. Ajoutez un encodeur de mot de passe dans la classe SecurityConfig et appelez-la pour coder le mot de passe de l'utilisateur dans la méthode globalUserDetails. Le codeur est nécessaire car vous utilisez des mots de passe en mémoire. Donc, sans application de codeur de mot de passe échoue avec une erreur: 

    Encoded password does not look like BCrypt
    

Fragment de code ci-dessous

@Autowired
public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception {
    PasswordEncoder passwordEncoder = passwordEncoder();
    auth.inMemoryAuthentication().passwordEncoder(passwordEncoder()).
            withUser("bill").password(passwordEncoder.encode("abc123")).roles("ADMIN").and()
            .withUser("$2a$10$TT7USzDvMxMZvf0HUVh9p.er1GGnjNQzlcGivj8CivnaZf9edaz6C")
            .password("$2a$10$TT7USzDvMxMZvf0HUVh9p.er1GGnjNQzlcGivj8CivnaZf9edaz6C").roles("USER");
}

@Bean
public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
}

J'espère que ça aide. J'ai créé une branche pour votre projet mais je ne pouvais pas le pousser à cause de 403. Donc tout le code nécessaire est là dans ma réponse.

1
Alexander Petrov

Lorsque vous activez un serveur de ressources, vous devez configurer l'URL check_token afin qu'il puisse atteindre le serveur d'autorisation OAuth2 et valider le code d'accès spécifié.

Vous pourriez faire quelque chose comme:

@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class OAuth2ResourceServerConfig extends GlobalMethodSecurityConfiguration {

    @Value("${oauth.url.internal}")    // e.g. http://localhost:8082/oauth
    private String oauthUrl;

    @Value("${oauth.client}")
    private String oauthClient;

    @Value("${oauth.secret}")
    private String oauthSecret;

    @Override
    protected MethodSecurityExpressionHandler createExpressionHandler() {
        return new OAuth2MethodSecurityExpressionHandler();
    }

    @Primary
    @Bean
    public RemoteTokenServices tokenService() {
        RemoteTokenServices tokenService = new RemoteTokenServices();
        tokenService.setCheckTokenEndpointUrl(oauthUrl + "/check_token");
        tokenService.setClientId(oauthClient);
        tokenService.setClientSecret(oauthSecret);
        return tokenService;
    }
}

En outre, vous pouvez ignorer les points de terminaison spécifiques à Swagger:

@Configuration
public class SecurityConfig 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/**");
    }
}

Juste au cas où, c’est la classe que j’ai implémentée pour l’autorisation Swagger w/OAuth2:

@EnableSwagger2
@Configuration
public class SwaggerConfig implements WebMvcConfigurer {

    private static final String BASE_PACKAGE = "com.somepackage.api";

    @Value("${oauth.url}")    // Make sure this is an external URL, i.e. accessible from Swagger UI
    private String oauthUrl;

    @Value("${swagger.scopes}")
    private String swaggerScopes;

    @Value("${swagger.urls}")
    private String swaggerUrls;    // Your v2/api-docs URL accessible from the UI

    @Bean
    public Docket api(){
        return new Docket(DocumentationType.SWAGGER_2)
            .select()
            .apis(RequestHandlerSelectors.basePackage(BASE_PACKAGE))
            .apis(RequestHandlerSelectors.any())
            .paths(PathSelectors.any())
            .build()
            .securitySchemes(Collections.singletonList(securitySchema()))
            .securityContexts(Collections.singletonList(securityContext()));
    }

    private OAuth securitySchema() {
        List<AuthorizationScope> authorizationScopeList = new ArrayList<>();
        authorizationScopeList.add(new AuthorizationScope(swaggerScopes, ""));

        List<GrantType> grantTypes = new ArrayList<>();
        GrantType creGrant = new ResourceOwnerPasswordCredentialsGrant(oauthUrl + "/token");
        grantTypes.add(creGrant);

        return new OAuth("oauth2schema", authorizationScopeList, grantTypes);
    }

    private SecurityContext securityContext() {
        return SecurityContext.builder().securityReferences(defaultAuth()).forPaths(PathSelectors.ant(swaggerUrls)).build();
    }

    private List<SecurityReference> defaultAuth() {
        final AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
        authorizationScopes[0] = new AuthorizationScope(swaggerScopes, "");
        return Collections.singletonList(new SecurityReference("oauth2schema", authorizationScopes));
    }

    @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/");
    }
}

Versions:

  • springSecurityVersion = '2.0.5.RELEASE'
  • swaggerVersion = '2.8.0'
  • springBootVersion = '2.0.5.RELEASE'
1
Fabio Manzano