web-dev-qa-db-fra.com

Impossible d'accéder aux ressources avec access_token: Spring Boot Oauth2

J'essaie d'implémenter Oauth2 dans mon application existante. Au départ, j'ai ajouté une sécurité de printemps, puis essayé d'ajouter oauth2. Après l'ajout de la configuration, je peux générer access_token, mais en utilisant access_token, je ne peux pas accéder aux ressources.

Voici mon code:

SecurityConfiguration.Java

    @Configuration
    @EnableWebSecurity
    public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    private DataSource dataSource;

    @Autowired
    private ClientDetailsService clientDetailsService;

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/resources/**");
    }

    @Autowired
    public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception {
        auth.jdbcAuthentication().dataSource(dataSource);
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers("/", "/patients").permitAll()
                .antMatchers("/oauth/token").permitAll()
                .anyRequest().authenticated()
                .and().httpBasic();
        http.csrf().disable();
    }

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.jdbcAuthentication().dataSource(dataSource)
                .usersByUsernameQuery("select username, password, 1 as enabled from user where username=?")
                .authoritiesByUsernameQuery("select username, authority from authorities where username=?");
    }

    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Bean
    public JdbcTokenStore tokenStore() {
        return new JdbcTokenStore(dataSource);
    }

    @Bean
    @Autowired
    public TokenStoreUserApprovalHandler userApprovalHandler(TokenStore tokenStore) {
        TokenStoreUserApprovalHandler handler = new TokenStoreUserApprovalHandler();
        handler.setTokenStore(tokenStore);
        handler.setRequestFactory(new DefaultOAuth2RequestFactory(clientDetailsService));
        handler.setClientDetailsService(clientDetailsService);
        return handler;
    }

    @Bean
    @Autowired
    public ApprovalStore approvalStore(TokenStore tokenStore) throws Exception {
        TokenApprovalStore store = new TokenApprovalStore();
        store.setTokenStore(tokenStore);
        return store;
    }
}

SecurityOAuth2Configuration.Java

@Configuration
@EnableAuthorizationServer
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Import(SecurityConfiguration.class)
public class SecurityOAuth2Configuration extends AuthorizationServerConfigurerAdapter {
    private static String REALM = "CRM_REALM";
    private static final int ONE_DAY = 60 * 60 * 24;
    private static final int THIRTY_DAYS = 60 * 60 * 24 * 30;

    @Autowired
    private TokenStore tokenStore;

    @Autowired
    private DataSource dataSource;

    @Autowired
    private UserApprovalHandler userApprovalHandler;

    @Autowired
    @Qualifier("authenticationManagerBean")
    private AuthenticationManager authenticationManager;

    @Override
    public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
        oauthServer.realm(REALM);
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.jdbc(dataSource);
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.tokenStore(tokenStore).userApprovalHandler(userApprovalHandler)
                .authenticationManager(authenticationManager);
    }
}

ResourceServer.Java

@Configuration
@EnableResourceServer
public class ResourceServer extends ResourceServerConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.anonymous().disable()
                .requestMatchers().antMatchers("/patients/**").and().authorizeRequests()
                .antMatchers("/patient/**").access("hasRole('USER')")
                .and().exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());
    }

}

J'ai utilisé this tutorial pour référence.

Je peux obtenir un jeton d'accès à l'aide des informations d'identification d'authentification de base.

 enter image description here

Mais quand j'ai utilisé le même jeton d'accès pour obtenir des ressources, cela a échoué .  enter image description here

J'ai ajouté toutes les tables requises pour oauth . Est-ce qu'il me manque quelque chose?

Mise à jour:

J'ai supprimé .and().httpBasic(); et Ajouté @Order (3) dans WebsecurityConfigurerAdapter et mis à jour le fichier de propriétés avec security.oauth2.resource.filter-order = 3

maintenant obtenir une erreur en tant que { "timestamp": 1543500350487, "status": 403, "error": "Forbidden", "message": "Access Denied", "path": "/patient/1/" }

Mise à jour 2

voici le schéma de mon utilisateur et de mes autorités:

utilisateur +----------+-----------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +----------+-----------------+------+-----+---------+----------------+ | id | int(6) unsigned | NO | PRI | NULL | auto_increment | | username | varchar(50) | NO | UNI | NULL | | | password | varchar(100) | NO | | NULL | | +----------+-----------------+------+-----+---------+----------------+

autorités +-----------+-----------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-----------+-----------------+------+-----+---------+----------------+ | id | int(6) unsigned | NO | PRI | NULL | auto_increment | | username | varchar(50) | NO | MUL | NULL | | | authority | varchar(50) | NO | | NULL | | +-----------+-----------------+------+-----+---------+----------------+

7
vjnan369

Vous devez utiliser hasRole directement sur votre antmatcher au lieu d’une chaîne dans la fonction access(). Cela évaluera la variable hasRole correctement et déterminera correctement que l'utilisateur a accès à la ressource demandée.

Cela se traduira par le code suivant pour ResourceServer.Java:

@Configuration
@EnableResourceServer
public class ResourceServer extends ResourceServerConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.anonymous().disable()
                .requestMatchers().antMatchers("/patients/**").and().authorizeRequests()
                .antMatchers("/patient/**").hasRole('USER')
                .and().exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());
    }

}
4
Sven Hakvoort

Tout d’abord, vous avez deux méthodes similaires qui modifient la AuthenticationManagerBuilder

@Autowired
public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception {

et

@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {

Y a-t-il une raison pour laquelle les deux sont là? Je n'ai pas cela dans ma configuration configurée. 

De plus, votre requête peut ne pas fonctionner correctement. Vous devez suivre certaines instructions pour configurer un service utilisateur afin de gérer l'appel loaduserbyusername et l'objet auth avec un. Remarque: je n'ai pas la même configuration AuthenticationManagerBuilder que vous, le mien est configuré pour utiliser un service userdetails, avec un mot de passe Encoder like so.

    auth.userDetailsService(securityUserService)
        .passwordEncoder(passwordEncoders.userPasswordEncoder());

Si cela ne vous aide pas, voici une autre façon de configurer:

Remplacez la classe qui étend WebSecurityConfigurerAdapter par ne concerne que le point de terminaison du jeton.

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
    .authorizeRequests()
        .antMatchers("/api/oauth/**").permitAll()
        .and()
    .csrf()
        .disable();
}

Maintenant, dans votre ResourceServerConfigurerAdapter, laissez la configuration s'inquiéter de tout ce qui se trouve dans le serveur de ressources. Veuillez noter que cela ne fonctionnera que si votre configuration AuthenticationManagerBuilder charge correctement le rôle. Comme d'autres l'ont noté, Spring a le préfixe ROLE_. Qui pour une raison quelconque, vous récupérez en utilisant une requête, et ils sont des autorités.

@Override
public void configure(HttpSecurity http) throws Exception {

    http.csrf().disable()
    .requestMatchers()
        .antMatchers("/api/**")
        .and()
    .authorizeRequests()
        .antMatchers("/api/**").access("hasRole('USER')")
        .and()
    .exceptionHandling()
    .accessDeniedHandler(new OAuth2AccessDeniedHandler());

}

Dans mon fichier AuthServerConfig, je n'ai pas les annotations suivantes:

@EnableGlobalMethodSecurity(prePostEnabled = true)
@Import(SecurityConfiguration.class)

Je configure la AuthorizationServerSecurityConfigurer différemment du tutoriel que vous avez suivi, le mien est le suivant:

@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {

    oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
}

Ma ClientDetailsServiceConfigurer est toujours en mémoire, donc c'est différent aussi. Ma AuthorizationServerEndpointsConfigurer est également légèrement différente, je n’ajoute qu’un magasin de jetons, une chaîne de rehausseurs (ne vous inquiétez pas, c’est extra), et une authenticationManager

    endpoints
        .tokenStore(tokenStore())
        .tokenEnhancer(tokenEnhancerChain)
        .authenticationManager(authenticationManager);
3
Edwin Diaz-Mendez

Veuillez changer le code comme ci-dessous dans ResourceServer:

Regardez cette ligne:

http.anonymous().disable()
                .requestMatchers().antMatchers("/patients/**","/patient/**")

Etant donné que "/ patient/" **, n’a pas été ajouté à la requête correspondante, la demande a été traitée par un autre configuration

package project.configuration;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler;


@Configuration
@EnableResourceServer
public class ResourceServer extends ResourceServerConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.anonymous().disable()
                .requestMatchers().antMatchers("/patients/**","/patient/**").and().
                authorizeRequests().antMatchers("*/patient/**").hasRole("USER")
                .and().exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());
    }

}
0
secret super star

Je soupçonne que le problème pourrait être la façon dont vous sauvegardez/chargez des rôles. Dans Spring Security, il existe un préfixe par défaut pour les rôles: ROLE_. Donc, dans votre base de données (stockage), vous devez les enregistrer sous le nom ROLE_FOO par exemple, puis vous pouvez utiliser hasRole('FOO').

J'ai trouvé le même problème ici, et ma réponse a semblé résoudre le problème: https://stackoverflow.com/a/43568599/4473822

La personne qui a eu le problème avait également 403 - Forbidden et l'enregistrement correct des rôles dans la base de données a résolu le problème.

Vous pouvez également modifier le préfixe par défaut, mais je ne le recommanderais pas, à moins que vous ne souhaitiez jouer avec Spring un peu.

0
Tom