Spring 使用资源服务器启动 2.0 OAuth2 授权服务器

Spring Boot 2.0 OAuth2 Authorization Server with Ressource Server

我试图创建一个授权服务器,它有自己的登录页面和一个资源 Spring Boot 2.0.0 和 spring-security-oauth2 2.3.0。不幸的是,资源服务器的配置似乎不起作用。随着

curl -v localhost:8080/sample

总是重定向 302 到 localhost:8080/login 有或没有令牌。

我的安全配置是

@Configuration
public class SecurityConfiguration {

   @Configuration
   @Order(1)
   @EnableWebSecurity(debug = true)
   protected static class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

      @Override
      protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
         auth.inMemoryAuthentication().withUser("john").password("{noop}123").roles("User");
      }

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

      @Override
      protected void configure(final HttpSecurity http) throws Exception {
         http.authorizeRequests()
         .antMatchers("/ping").permitAll()
         .antMatchers("/login").permitAll()
         .anyRequest().authenticated()
         .and()
         .csrf()
         .and()
         .formLogin()
         .usernameParameter("username")
         .passwordParameter("password")
         .loginPage("/login")
         .permitAll()
               .and()
               .rememberMe()
               .rememberMeParameter("remember")
         .and()
         .httpBasic().disable()
         .logout().permitAll();
      }
   }

   @Configuration
   @EnableResourceServer
   @Order(10)
   protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {

      private static final String RESOURCE_ID = "Sample";

      @Override
      public void configure(final ResourceServerSecurityConfigurer resources) throws Exception {
         resources.resourceId(RESOURCE_ID);
      }

      @Override
      public void configure(final HttpSecurity http) throws Exception {
         http.authorizeRequests()
         .antMatchers("/sample**").authenticated();
      }
   }

   @Configuration
   @EnableAuthorizationServer
   @Order(Ordered.HIGHEST_PRECEDENCE)
   protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {

      @Autowired
      private AuthenticationManager authenticationManager;

      @Override
      public void configure(final AuthorizationServerSecurityConfigurer security) throws Exception {
         security.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
      }

      @Override
      public void configure(final ClientDetailsServiceConfigurer clients) throws Exception {
         clients.inMemory().withClient("ABC").secret("{noop}sec1").autoApprove(true)
         .authorizedGrantTypes("authorization_code", "client_credentials", "password", "refresh_token")
         .scopes("read", "write")
         .redirectUris("http://google.com");
      }

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

   }
}

如何正确配置资源服务器?

Download Example Project

更新:

我使用 Spring Boot 1.5.10、spring-security-oauth2 2.0.14 和 Spring Boot 2.0.0、spring- 测试了以下配置安全-oauth2 2.3.0。

在 1.5.10 中它工作正常,但在 2.0.0 中我在处理登录时得到 "There was an unexpected error (type=Method Not Allowed, status=405)."。我看到安全过滤器链中缺少 UsernamePasswordAuthenticationFilter

我错过了 Spring Boot 2.0.0 或 Spring Security 5.0.3 中的重大更改吗?

@Configuration
@EnableWebMvc
@EnableAuthorizationServer
@EnableResourceServer
@EnableWebSecurity(debug = true)
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
public class SecurityConfiguration {


   @Configuration
   protected static class WebMvcConfiguration extends WebMvcConfigurerAdapter implements WebMvcConfigurer {

      @Override
      public void addViewControllers(final ViewControllerRegistry registry) {
         registry.addViewController("/login").setViewName("login");
         registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
      }

   }

   @Configuration
   protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {

      private static final String RESOURCE_ID = "Sample";

      @Override
      public void configure(final ResourceServerSecurityConfigurer resources) throws Exception {
         resources.resourceId(RESOURCE_ID);
      }

      @Override
      public void configure(final HttpSecurity http) throws Exception {
         http
         .authorizeRequests()
         .antMatchers("/sample**").authenticated()
         ;
      }
   }

   @Configuration
   protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {

      @Autowired
      private AuthenticationManager authenticationManager;

      @Override
      public void configure(final AuthorizationServerSecurityConfigurer security) throws Exception {
         security
         .tokenKeyAccess("permitAll()")
         .checkTokenAccess("isAuthenticated()")
         ;
      }

      @Override
      public void configure(final ClientDetailsServiceConfigurer clients) throws Exception {
         clients
         .inMemory()
         .withClient("ABC")
         .secret("{noop}sec1")
         .autoApprove(true)
         .authorizedGrantTypes("authorization_code", "client_credentials", "password", "refresh_token")
         .scopes("read", "write")
         .redirectUris("http://google.com")
         ;
      }

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

   }


   @Configuration
   protected static class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

      @Override
      protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
         auth
               .inMemoryAuthentication()
               .withUser("john")
               .password("{noop}123")
               .roles("User");
      }

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

      @Override
      protected void configure(final HttpSecurity http) throws Exception {
         http
         .requestMatchers()
         .antMatchers("/ping")
         .antMatchers("/login")
         .antMatchers("/oauth/**")
         .and()
         .authorizeRequests()
         .antMatchers("/ping").permitAll()
         .anyRequest().authenticated()
         .and()
         .csrf()
         .and()
         .formLogin()
         .usernameParameter("username")
         .passwordParameter("password")
         .loginPage("/login")
         .permitAll()
         .and()
         .rememberMe()
         .rememberMeParameter("remember")
         .and()
         .httpBasic().disable()
         .logout().permitAll();

      }
   }
}

感谢dur的指点,问题已解决。

此配置有效:

@Configuration
@EnableWebMvc
@EnableAuthorizationServer
@EnableResourceServer
@EnableWebSecurity(debug = true)
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
public class SecurityConfiguration {


   @Configuration
   protected static class WebMvcConfiguration implements WebMvcConfigurer {

      @Override
      public void addViewControllers(final ViewControllerRegistry registry) {
         registry.addViewController("/login").setViewName("login");
         registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
      }

   }

   @Configuration
   @Order(2)
   protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {

      private static final String RESOURCE_ID = "Sample";

      @Override
      public void configure(final ResourceServerSecurityConfigurer resources) throws Exception {
         resources.resourceId(RESOURCE_ID);
      }

      @Override
      public void configure(final HttpSecurity http) throws Exception {
         http
         .authorizeRequests()
         .antMatchers("/sample**").authenticated()
         ;
      }
   }

   @Configuration
   protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {

      @Autowired
      private AuthenticationManager authenticationManager;

      @Override
      public void configure(final AuthorizationServerSecurityConfigurer security) throws Exception {
         security
         .tokenKeyAccess("permitAll()")
         .checkTokenAccess("isAuthenticated()")
         ;
      }

      @Override
      public void configure(final ClientDetailsServiceConfigurer clients) throws Exception {
         clients
         .inMemory()
         .withClient("ABC")
         .secret("{noop}sec1")
         .autoApprove(true)
         .authorizedGrantTypes("authorization_code", "client_credentials", "password", "refresh_token")
         .scopes("read", "write")
         .redirectUris("http://google.com")
         ;
      }

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

   }


   @Configuration
   @Order(1)
   protected static class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

      @Override
      protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
         auth
         .inMemoryAuthentication()
         .withUser("john")
         .password("{noop}123")
         .roles("User");
      }

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

      @Override
      protected void configure(final HttpSecurity http) throws Exception {
         http
         .requestMatchers()
         .antMatchers("/ping")
         .antMatchers("/login")
         .antMatchers("/oauth/**")
         .and()
         .authorizeRequests()
         .antMatchers("/ping").permitAll()
         .anyRequest().authenticated()
         .and()
         .csrf()
         .and()
         .formLogin()
         .usernameParameter("username")
         .passwordParameter("password")
         .loginPage("/login")
         .permitAll()
         .and()
         .rememberMe()
         .rememberMeParameter("remember")
         .and()
         .httpBasic().disable()
         .logout().permitAll();

      }
   }
}

写了一个基本的 spring boot 2 oauth2 资源服务器和授权服务器,把它放在这里以防有人正在寻找 bootstrap 项目:

https://github.com/indrekru/spring-boot-2-oauth2-resource-server