wake-up-neo.com

Spring Boot2 Oauth2 Implicit Flow - http: // localhost: 8080/oauth/autorisieren, Zugriff verweigert zu bekommen

Ich habe eine Spring Boot 2-Anwendung erstellt, die SpringFox Swagger 2.8.0 mit implizitem Oauth2 Grant für die Authentifizierung und Autorisierung integriert hat.

Der Code funktioniert einwandfrei, aber wenn ich auf die Schaltfläche "Autorisieren" klicke, wird auf den Code umgeleitet 

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-redirect read & state = U3VuIE9jdCAxNCAyMDE4IDIwOjQyOjUwIEdNVCswNTMwIChJbmRpYSBTdGFuZGFyZCBUaW1lKQ% 3D

zeigt jedoch Zugriff verweigert wie unten gezeigt. 

Mein gesamtes Projekt ist in GitHub verfügbar.

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

Update 1

Ich habe die Sicherheit und den passwordencoder configure aus @AlexanderPetrov hinzugefügt. Die Dinge funktionieren gut, wenn ich @EnableResourceServer hinzufüge, dass auf dem Anmeldebildschirm angezeigt wird. Für den Zugriff auf diese Ressource ist eine vollständige Authentifizierung erforderlich (siehe unten)

 enter image description here

Kann mir bitte jemand weiterhelfen?

7
Alex Man

Sie müssen die folgenden Änderungen in Ihrem Code vornehmen

  1. Für den impliziten Fluss ist eine Anmeldekonfiguration erforderlich. 
  2. Wenn Sie impliziten Datenfluss verwenden, wird das Token durch die Berechtigungs-URL anstelle der Token-URL generiert. Sie müssen also "/ oauth/token" in "oauth/authorize" ändern. Konfigurieren Sie die Methode unten 

    @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. Fügen Sie den Kennwortcodierer in der Klasse SecurityConfig hinzu und rufen Sie ihn auf, um das Benutzerpasswort in der Methode globalUserDetails zu codieren. Encoder ist notwendig, da Sie im Speicher Kennwörter verwenden. Ohne Passwortgeber schlägt also die Anwendung mit einem Fehler fehl: 

    Encoded password does not look like BCrypt
    

Code-Fragment unten

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

Ich hoffe es hilft. Ich habe einen Zweig für Ihr Projekt erstellt, konnte es aber wegen 403 nicht schieben. Daher ist der gesamte erforderliche Code hier in meiner Antwort.

1

Wenn Sie einen Ressourcenserver aktivieren, müssen Sie die URL check_token so konfigurieren, dass sie den OAuth2-Autorisierungsserver erreichen und das angegebene access_token überprüfen kann.

Sie könnten so etwas tun:

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

Darüber hinaus möchten Sie möglicherweise Swagger-spezifische Endpunkte ignorieren:

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

Für den Fall ist dies die Klasse, die ich für die Berechtigung von Swagger mit OAuth2 implementiert habe:

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

Versionen:

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