it-swarm.com.de

Zugriff auf Ressourcen mit access_token nicht möglich: Spring Boot Oauth2

Ich versuche, Oauth2 in meine vorhandene Anwendung zu implementieren. Zunächst habe ich die Frühlingssicherheit hinzugefügt und dann versucht, oauth2 hinzuzufügen. Nach dem Hinzufügen der Konfiguration kann ich access_token generieren, aber mit access_token kann ich nicht auf Ressourcen zugreifen.

Hier ist mein 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());
    }

}

Ich habe dieses Tutorial als Referenz verwendet.

Ich kann das Zugriffstoken mit grundlegenden Anmeldeinformationen abrufen.

 enter image description here

Aber wenn ich das gleiche Zugriffstoken zum Abrufen von Ressourcen verwendet habe, schlägt dies fehl.  enter image description here

Ich habe alle erforderlichen Tabellen für oauth hinzugefügt. Fehlt mir etwas?

Update:

Ich habe .and().httpBasic(); entfernt und @Order (3) in WebsecurityConfigurerAdapter hinzugefügt und die Eigenschaftendatei mit security.oauth2.resource.filter-order = 3 aktualisiert.

fehler wird jetzt als { "timestamp": 1543500350487, "status": 403, "error": "Forbidden", "message": "Access Denied", "path": "/patient/1/" } angezeigt

Update 2

hier ist mein Benutzer- und Berechtigungsschema:

user +----------+-----------------+------+-----+---------+----------------+ | 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 | | +----------+-----------------+------+-----+---------+----------------+

Authorities +-----------+-----------------+------+-----+---------+----------------+ | 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

Sie sollten hasRole direkt in Ihrem Antmatcher anstelle einer Zeichenfolge in der Funktion access() verwenden. Dadurch wird die hasRole richtig ausgewertet und der Benutzer kann auf die angeforderte Ressource zugreifen.

Dies führt zu dem folgenden Code für 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

Zunächst haben Sie zwei ähnliche Methoden, die AuthenticationManagerBuilder ändern.

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

und

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

Gibt es einen Grund, warum beide da sind? Ich habe dies nicht in meiner Config eingerichtet. 

Darüber hinaus funktioniert Ihre Abfrage möglicherweise nicht ordnungsgemäß. Befolgen Sie einige Richtlinien zum Einrichten eines Benutzerdienstes, um den Aufruf loaduserbyusername und das Objekt auth mit einem zu behandeln. Zur Anmerkung: Ich habe nicht dieselbe AuthenticationManagerBuilder wie Sie eingerichtet, ich habe meinen Benutzer so konfiguriert, dass er einen Userdetails-Dienst verwendet, zusammen mit einem Passwort-Encoder.

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

Wenn das nicht hilft, können Sie die Konfiguration alternativ durchführen:

Ändern Sie die Klasse, die sich WebSecurityConfigurerAdapter in erweitert, nur um den Tokenendpunkt.

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

Sorgen Sie jetzt in Ihrem ResourceServerConfigurerAdapter für die Konfiguration des Ressourcen-Servers. Bitte beachten Sie, dass dies nur funktioniert, wenn Ihre AuthenticationManagerBuilder-Konfiguration die Rolle korrekt lädt. Wie andere schon bemerkt haben, hat Spring das Präfix ROLE_. Was Sie aus irgendeinem Grund mithilfe einer Abfrage abrufen, und dies sind Berechtigungen.

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

}

In meiner AuthServerConfig-Datei habe ich nicht die folgenden Anmerkungen:

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

Ich konfiguriere das AuthorizationServerSecurityConfigurer anders als das Tutorial, das Sie befolgt haben, mein ist folgendes:

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

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

Mein ClientDetailsServiceConfigurer ist noch im Speicher, das ist also auch anders. Mein AuthorizationServerEndpointsConfigurer ist auch etwas anders, ich füge nur einen Tokenstore, eine Enhancer-Kette hinzu (Mach dir keine Sorgen, es ist extra) und einen authenticationManager

    endpoints
        .tokenStore(tokenStore())
        .tokenEnhancer(tokenEnhancerChain)
        .authenticationManager(authenticationManager);
3

Bitte ändern Sie den Code wie folgt in ResourceServer:

Schauen Sie sich diese Zeile an:

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

Da "/ patient/" ** nicht als Teil des Request Matchers hinzugefügt wird, wurde die Anfrage tatsächlich von anderen configuration verarbeitet.

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

Ich vermute, das Problem liegt möglicherweise in der Art, wie Sie Rollen speichern/laden. In der Frühlingssicherheit gibt es ein Standardpräfix für Rollen: ROLE_. In Ihrer Datenbank (Speicher) müssen Sie sie zum Beispiel als ROLE_FOO speichern, und dann können Sie hasRole('FOO') verwenden.

Ich fand das gleiche Problem hier und meine Antwort schien das Problem zu lösen: https://stackoverflow.com/a/43568599/4473822

Die Person, die das Problem hatte, hatte ebenfalls 403 - Forbidden und das korrekte Speichern der Rollen in der Datenbank löste das Problem.

Sie können auch das Standardpräfix ändern. Ich würde es jedoch nicht empfehlen, es sei denn, Sie möchten sich mit dem Frühling etwas verwirren.

0
Tom