web-dev-qa-db-ja.com

access_tokenでリソースにアクセスできない:スプリングブートOauth2

既存のアプリケーションにOauth2を実装しようとしています。最初にSpringのセキュリティを追加してから、oauth2を追加しようとしました。構成を追加した後、access_tokenを生成できますが、access_tokenを使用してリソースにアクセスできません。

これが私のコードです:

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

}
_

参考のために this チュートリアルを使用しました。

基本的な認証情報を使用してアクセストークンを取得できます。

enter image description here

しかし、同じアクセストークンを使用してリソースを取得すると、失敗します。 enter image description here

Oauthに必要なすべてのテーブルを追加しました。何か足りないものはありますか?

更新:

.and().httpBasic();を削除し、WebSecurityConfigurerAdapterに@Order(3)を追加し、_security.oauth2.resource.filter-order = 3_でプロパティファイルを更新しました

_{ "timestamp": 1543500350487, "status": 403, "error": "Forbidden", "message": "Access Denied", "path": "/patient/1/" }_としてエラーが発生する

更新2

これが私のユーザーと権限のスキーマです:

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

8
vjnan369

access()関数内の文字列の代わりに、antmatcherで直接hasRoleを使用する必要があります。これにより、hasRoleが正しく評価され、ユーザーがリクエストされたリソースにアクセスできることが正しく判断されます。

これにより、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());
    }

}
5
Sven Hakvoort

まず、AuthenticationManagerBuilderを変更する2つの類似したメソッドがあります。

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

そして

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

両方が存在する理由はありますか?私の設定にはこれがありません。

さらに、クエリが正しく機能していない可能性があります。 loaduserbyusername呼び出しとauthオブジェクトを処理するユーザーサービスを設定する方法については、いくつかのガイドラインに従う必要があります。注:私はあなたと同じAuthenticationManagerBuilderを設定していません私はuserEndetailsサービスとパスワードEncoderそうです。

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

それでも問題が解決しない場合は、次の代替構成方法を使用してください。

WebSecurityConfigurerAdapterを拡張するクラスをに変更し、トークンエンドポイントにのみ関係します。

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

次に、ResourceServerConfigurerAdapterで、リソースサーバーの構成について心配するように構成します。これが機能するのは、AuthenticationManagerBuilder構成がロールを正しくロードしている場合のみであることに注意してください。他の人が指摘したように、SpringにはプレフィックスROLE_が付いています。なんらかの理由でクエリを使用して取得しているものであり、それらは権限です。

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

}

私のAuthServerConfigファイルには、次の注釈はありません。

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

私はAuthorizationServerSecurityConfigurerをあなたが従ったチュートリアルとは異なる方法で設定しました。

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

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

私のClientDetailsServiceConfigurerはまだメモリ内にあるので、それも異なります。私のAuthorizationServerEndpointsConfigurerも少し異なります。追加するのは、トークンストア、エンハンサーチェーン(これは心配する必要はありません。追加です)、およびauthenticationManagerだけです。

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

ResourceServerで以下のようにコードを変更してください:

この行を見てください:

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

"/ patient /" **はリクエストマッチャーの一部として追加されないため、リクエストは実際には他の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

問題は、ロールを保存/ロードする方法にあるのではないかと思います。春のセキュリティでは、ロールのデフォルトのプレフィックスがあります:_ROLE__。したがって、DB(ストレージ)で、たとえば、それらを_ROLE_FOO_として保存する必要があります。その後、hasRole('FOO')を使用できます。

私はここで同じ問題を見つけました、そして私の答えは問題を解決するようでした: https://stackoverflow.com/a/43568599/4473822

問題が発生した人にも_403 - Forbidden_があり、ロールをDBに正しく保存すると問題が解決しました。

デフォルトの接頭辞を変更することもできますが、少しばねをいじくりたくなければ、お勧めしません。

0
Tom