【问题标题】:404 No mapping found for HTTP request with URI after oauth2 successful authorization404 oauth2 授权成功后,未找到带有 URI 的 HTTP 请求的映射
【发布时间】:2014-10-23 04:10:11
【问题描述】:

我对 Spring REST oAuth2 配置有疑问。 Springs 看到并映射了我的 URL,但是在 oauth2 安全检查(成功)声称没有匹配的 URL 之后。但我不知道为什么,因为 Spring 在应用程序初始化时看到了它。 我能够正确地使用 /oauth/token 进行身份验证并生成令牌。 我只是无法处理不需要令牌授权的请求。

Spring 4.0.6、spring-security 3.2.4、Spring-security-oauth2 2.0.1

上下文初始化的日志

2014-08-29 08:56:26.415 [Scanner-1] INFO  o.s.w.s.m.m.a.RequestMappingHandlerMapping - Mapped "{[/api/users/{email}],methods=[PUT],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.util.concurrent.Callable<org.springframework.http.ResponseEntity> com.example.user.UserCommandsController.update(java.lang.String)
2014-08-29 08:56:26.416 [Scanner-1] INFO  o.s.w.s.m.m.a.RequestMappingHandlerMapping - Mapped "{[/api/users/{email}],methods=[DELETE],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.util.concurrent.Callable<org.springframework.http.ResponseEntity> com.example.user.UserCommandsController.delete(java.lang.String)
2014-08-29 08:56:26.416 [Scanner-1] INFO  o.s.w.s.m.m.a.RequestMappingHandlerMapping - Mapped "{[/api/users/logout],methods=[POST],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.util.concurrent.Callable<org.springframework.http.ResponseEntity> com.example.user.UserCommandsController.logout()
2014-08-29 08:56:26.416 [Scanner-1] INFO  o.s.w.s.m.m.a.RequestMappingHandlerMapping - Mapped "{[/api/users],methods=[POST],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.util.concurrent.Callable<org.springframework.http.ResponseEntity<java.lang.Void>> com.example.user.UserCommandsController.signup(java.lang.String,java.lang.String)

发送请求后

2014-08-29 09:00:58.654 [qtp1157726741-28] DEBUG o.s.s.w.u.m.AntPathRequestMatcher - Checking match of request : '/api/users'; against '/api/users'
2014-08-29 09:00:58.654 [qtp1157726741-28] DEBUG o.s.s.w.a.i.FilterSecurityInterceptor - Secure object: FilterInvocation: URL: /api/users; Attributes: [permitAll]
2014-08-29 09:00:58.654 [qtp1157726741-28] DEBUG o.s.s.w.a.i.FilterSecurityInterceptor - Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@9055c2bc: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS
2014-08-29 09:00:58.654 [qtp1157726741-28] DEBUG o.s.s.a.vote.AffirmativeBased - Voter: org.springframework.security.web.access.expression.WebExpressionVoter@31b7d21c, returned: 1
2014-08-29 09:00:58.654 [qtp1157726741-28] DEBUG o.s.s.w.a.i.FilterSecurityInterceptor - Authorization successful
2014-08-29 09:00:58.654 [qtp1157726741-28] DEBUG o.s.s.w.a.i.FilterSecurityInterceptor - RunAsManager did not change Authentication object
2014-08-29 09:00:58.654 [qtp1157726741-28] DEBUG o.s.s.web.FilterChainProxy - /api/users reached end of additional filter chain; proceeding with original chain
2014-08-29 09:00:58.655 [qtp1157726741-28] DEBUG o.s.w.servlet.DispatcherServlet - DispatcherServlet with name 'dispatcher' processing POST request for [/api/users]
2014-08-29 09:00:58.655 [qtp1157726741-28] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - Looking up handler method for path /api/users
2014-08-29 09:00:58.655 [qtp1157726741-28] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - Did not find handler method for [/api/users]
2014-08-29 09:00:58.655 [qtp1157726741-28] DEBUG o.s.s.o.p.e.FrameworkEndpointHandlerMapping - Looking up handler method for path /api/users
2014-08-29 09:00:58.655 [qtp1157726741-28] DEBUG o.s.s.o.p.e.FrameworkEndpointHandlerMapping - Did not find handler method for [/api/users]
2014-08-29 09:00:58.655 [qtp1157726741-28] WARN  o.s.web.servlet.PageNotFound - No mapping found for HTTP request with URI [/api/users] in DispatcherServlet with name 'dispatcher'

和配置

@Configuration
@EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) {
        resources.resourceId("sample-resource-id");
    }

    @Override
    public void configure(final HttpSecurity http) throws Exception {
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        http
            .requestMatchers()
            .antMatchers(HttpMethod.POST, "/api/buildings/**")
            .antMatchers(HttpMethod.DELETE, "/api/**")
            .antMatchers(HttpMethod.PATCH, "/api/**")
            .antMatchers(HttpMethod.PUT, "/api/**")
            .and()
            .authorizeRequests()
            .antMatchers(HttpMethod.POST, "/api/buildings/**").access("hasRole('ROLE_USER')")
            .antMatchers(HttpMethod.DELETE, "/api/**").access("hasRole('ROLE_USER')")
            .antMatchers(HttpMethod.PATCH, "/api/**").access("hasRole('ROLE_USER')")
            .antMatchers(HttpMethod.PUT, "/api/**").access("hasRole('ROLE_USER')");
    }
}



@Controller
@EnableWebSecurity
@Profile("default")
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;

    /**
     * By default all request need authentication. Only those which do not need it, shall be specified explicitly.
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        http
            .csrf().disable();
        http
            .authorizeRequests()
            .antMatchers(HttpMethod.GET, "/api/buildings/**").permitAll()//to consider anonymous()
            .antMatchers(HttpMethod.POST, "/api/users").permitAll()//to consider anonymous()
            .antMatchers("/api/admin/**").hasRole("ADMIN")
            .anyRequest().authenticated();
    }

    @Override
    protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService);
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/app/**","/webjars/**", "/images/**", "/oauth/uncache_approvals", "/oauth/cache_approvals");
    }

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

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

部分用户控制器

@RestController
@RequestMapping("/api")
public class UserCommandsController {

    private final UserService userService;
    private AccountRecoveryMailer accountRecoveryMailer;
    private MessageSource messageSource;

    @Inject
    public UserCommandsController(final UserService userService, final AccountRecoveryMailer accountRecoveryMailer,
        final MessageSource messageSource) {
        this.userService = userService;
        this.accountRecoveryMailer = accountRecoveryMailer;
        this.messageSource = messageSource;
    }

    @RequestMapping(value = "/users", method = RequestMethod.POST)
    public Callable<ResponseEntity<Void>> signup(@RequestParam String email, @RequestParam String password) {
        return () -> {
            //do something
           };
    }
}

我想要实现的是保护所有请求,并且只有其中一些请求可以免费访问(或者可能只有 Authorization 标头与 client_id 匹配)。

【问题讨论】:

    标签: spring rest oauth spring-security-oauth2


    【解决方案1】:

    这是我的问题的解决方案。这个邪恶事物的根源是 bean 初始化,或者更好地说是它们的作用域。顺便说一句,不需要 SSL。

    下方配置错误,请勿盲目复制粘贴。

    我有两个 @ComponentScan 类。

    @Configuration
    @EnableWebMvc
    @ComponentScan(basePackageClasses = Application.class,
        excludeFilters = @Filter({RestController.class, Controller.class, Service.class, Repository.class, Configuration.class}))
    class WebMvcConfig extends WebMvcConfigurationSupport {
        //some code
    }
    
    @Configuration
    @ComponentScan(basePackageClasses = Application.class)
    class ApplicationConfig {
        //some code
    }
    

    还有我的 WebAppInitialization 代码

    @Order(2)
    public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
    
        @Override
        protected String[] getServletMappings() {
            return new String[]{"/"};
        }
    
        @Override
        protected Class<?>[] getRootConfigClasses() {
            return new Class<?>[]{ApplicationConfig.class, DataSourceConfig.class, SecurityConfig.class};
        }
    
        @Override
        protected Class<?>[] getServletConfigClasses() {
            return new Class<?>[]{WebMvcConfig.class};
        }
    
        @Override
        protected Filter[] getServletFilters() {
            CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
            characterEncodingFilter.setEncoding("UTF-8");
            characterEncodingFilter.setForceEncoding(true);
    
            return new Filter[]{characterEncodingFilter};
        }
    
        @Override
        protected void customizeRegistration(ServletRegistration.Dynamic registration) {
            registration.setInitParameter("defaultHtmlEscape", "true");
            registration.setInitParameter("spring.profiles.active", "default");
        }
    }
    

    如您所见,使用所有类型的 bean 的整个组件类路径扫描将在 getRootConfigClasses() 方法中初始化,而只有部分 bean 将在 getServletConfigClasses() 中初始化/em> 方法,由于 WebMvcConfig.class 及其在组件扫描中排除了某些 bean 类型。在我看来,这对 Spring 来说应该足够了,因为来自 rootContext 的 bean 可用于 servletContext。并且是,但仅用于 Web 应用程序实例化。 Spring Security oAuth2 还没有看到控制器映射。

    解决方案是去掉WebMvcConfig中的组件扫描,将getServletConfigClasses()方法改成这样:

    @Override
    protected Class<?>[] getServletConfigClasses() {
       return new Class<?>[]{ApplicationConfig.class, WebMvcConfig.class};
    }
    

    感谢 Spring bean 的热切缓存,一切都会好起来的。

    【讨论】:

      【解决方案2】:

      您使用 oAuth2 设置服务器,该服务器只能以安全方式 (https:) 访问。 如果您需要提供非安全(http:) 服务,则必须创建另一个服务器。

      让我们考虑一下,如果您家的门有锁,并且只有拥有钥匙的人才能进入您的家,那么您的家就是安全的。

      如果您在家中添加另一扇没有锁的门,您的家将变得不安全。

      如果您想制作无锁门,则应将该门安装到其他小屋以进行非安全使用。

      安全的家和不安全的小屋。 这些可能是你想在你的服务器上构建的。

      【讨论】:

      • 对不起,我的回答迟了。这显然是有道理的,但这仍然行不通。 curl -k -X POST https://localhost:8443/api/users --header "Content-Type:application/json"&lt;body&gt;&lt;h2&gt;HTTP ERROR 404&lt;/h2&gt; &lt;p&gt;Problem accessing /api/users. Reason: &lt;pre&gt; Not Found&lt;/pre&gt;&lt;/p&gt;&lt;hr&gt;&lt;i&gt;&lt;small&gt;Powered by Jetty://&lt;/small&gt;&lt;/i&gt;&lt;hr/&gt; &lt;/body&gt;
      猜你喜欢
      • 1970-01-01
      • 2017-07-16
      • 1970-01-01
      • 2016-02-05
      • 2014-12-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多