既存のアプリケーションに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 チュートリアルを使用しました。
基本的な認証情報を使用してアクセストークンを取得できます。
しかし、同じアクセストークンを使用してリソースを取得すると、失敗します。
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 | | +-----------+-----------------+------+-----+---------+----------------+
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());
}
}
まず、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);
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());
}
}
問題は、ロールを保存/ロードする方法にあるのではないかと思います。春のセキュリティでは、ロールのデフォルトのプレフィックスがあります:_ROLE_
_。したがって、DB(ストレージ)で、たとえば、それらを_ROLE_FOO
_として保存する必要があります。その後、hasRole('FOO')
を使用できます。
私はここで同じ問題を見つけました、そして私の答えは問題を解決するようでした: https://stackoverflow.com/a/43568599/4473822
問題が発生した人にも_403 - Forbidden
_があり、ロールをDBに正しく保存すると問題が解決しました。
デフォルトの接頭辞を変更することもできますが、少しばねをいじくりたくなければ、お勧めしません。