Spring Boot OAuth2 隐式流 + 表单登录和请求方法“POST"不支持错误 [英] Spring Boot OAuth2 implicit flow + form login and Request method 'POST' not supported error

查看:37
本文介绍了Spring Boot OAuth2 隐式流 + 表单登录和请求方法“POST"不支持错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的 Spring Boot 应用程序中,我试图配置 OAuth2 隐式流.为此,我正在尝试配置自定义登录表单.

这是我的配置:

@Configuration公共类 WebMvcConfig 扩展了 WebMvcConfigurerAdapter {@覆盖public void configureDefaultServletHandling(DefaultServletHandlerConfigurer 配置器) {配置器.启用();}@覆盖public void addViewControllers(ViewControllerRegistry 注册表) {registry.addViewController("/").setViewName("index");registry.addViewController("/login").setViewName("login");}@覆盖public void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");}}@配置@启用网络安全公共类 WebSecurityConfig 扩展了 WebSecurityConfigurerAdapter {@自动连线私人 SocialAuthenticationSuccessHandler socialAuthenticationSuccessHandler;@自动连线私有 DBUserDetailsS​​ervice userDetailsS​​ervice;@Value("${social.postLogin.url}")私人字符串 postLoginUrl;@覆盖公共无效配置(WebSecurity web)抛出异常{//Spring Security 忽略对 CSS 或 JS 等静态资源的请求//文件.web.ignoring().antMatchers("/static/**");}@覆盖protected void configure(HttpSecurity http) 抛出异常 {//@格式化程序:关闭http.addFilterBefore(new CorsFilter(), ChannelProcessingFilter.class);//在 SocialAuthenticationFilter 上设置一个自定义的 successHandler最终 SpringSocialConfigurer socialConfigurer = new SpringSocialConfigurer();socialConfigurer.addObjectPostProcessor(new ObjectPostProcessor() {@覆盖public <O extends SocialAuthenticationFilter>O postProcess(O socialAuthenticationFilter){socialAuthenticationFilter.setAuthenticationSuccessHandler(socialAuthenticationSuccessHandler);socialAuthenticationFilter.setPostLoginUrl(postLoginUrl);返回 socialAuthenticationFilter;}});http.csrf().disable().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests().antMatchers("/oauth/authorize").authenticated()//任何人都可以访问网址.antMatchers("/auth/**").permitAll().antMatchers("/actuator/health").permitAll().antMatchers("/actuator/**").hasAuthority("PERMISSION_READ_ACTUATOR_DATA").antMatchers("/login").permitAll().anyRequest().authenticated().and().formLogin().loginPage("/登录").loginProcessingUrl("/登录").usernameParameter("用户名").passwordParameter("密码").permitAll()//将 SocialAuthenticationFilter 添加到 Spring Security 的过滤器链..and()//应用来自 socialConfigurer 的配置(添加 SocialAuthenticationFilter).apply(socialConfigurer);//@格式化程序:打开}/*** 配置处理认证的认证管理器bean* 请求.*/@覆盖protected void configure(AuthenticationManagerBuilder auth) 抛出异常 {auth.userDetailsS​​ervice(userDetailsS​​ervice).passwordEncoder(new BCryptPasswordEncoder());}@覆盖@豆公共 AuthenticationManager authenticationManagerBean() 抛出异常 {返回 super.authenticationManagerBean();}}@配置公共类 OAuth2ServerConfig {私有静态最终字符串RESOURCE_ID =restservice";@自动连线私有 DBUserDetailsS​​ervice userDetailsS​​ervice;@豆@主要公共 DefaultTokenServices tokenServices() {DefaultTokenServices defaultTokenServices = new DefaultTokenServices();defaultTokenServices.setTokenStore(tokenStore());defaultTokenServices.setSupportRefreshToken(true);返回 defaultTokenServices;}@豆公共 JwtAccessTokenConverter accessTokenConverter() {JwtAccessTokenConverter 转换器 = 新 JwtAccessTokenConverter() {@覆盖公共 OAuth2AccessToken 增强(OAuth2AccessToken accessToken,OAuth2Authentication 认证){DBUserDetails user = (DBUserDetails) authentication.getUserAuthentication().getPrincipal();最终映射<字符串,对象>additionalInfo = new HashMap<>();additionalInfo.put("user_id", user.getUser().getId());((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);OAuth2AccessToken EnhancedToken = super.enhance(accessToken, authentication);返回增强令牌;}};转换器.setSigningKey("123");DefaultAccessTokenConverter accessTokenConverter = new DefaultAccessTokenConverter();DefaultUserAuthenticationConverter userTokenConverter = new DefaultUserAuthenticationConverter();userTokenConverter.setUserDetailsS​​ervice(userDetailsS​​ervice);accessTokenConverter.setUserTokenConverter(userTokenConverter);转换器.setAccessTokenConverter(accessTokenConverter);返回转换器;}@豆公共令牌商店令牌商店(){返回新的 JwtTokenStore(accessTokenConverter());}@配置@EnableAuthorizationServer受保护的静态类 AuthorizationServerConfiguration 扩展了 AuthorizationServerConfigurerAdapter {@自动连线@Qualifier("authenticationManagerBean")私有 AuthenticationManager authenticationManager;@自动连线私有 TokenStore 令牌存储;@自动连线私人 TokenEnhancer tokenEnhancer;@覆盖public void configure(AuthorizationServerEndpointsConfigurer endpoints) 抛出异常 {//@格式化程序:关闭端点.tokenStore(tokenStore).tokenEnhancer(tokenEnhancer).authenticationManager(this.authenticationManager);//@格式化程序:打开}@覆盖公共无效配置(ClientDetailsS​​erviceConfigurer 客户端)抛出异常 {//@格式化程序:关闭客户.inMemory().withClient("clientapp").authorizedGrantTypes("密码","re​​fresh_token")//.authorizedGrantTypes("隐式").authorities("ROLE_CLIENT").scopes("读", "写").resourceIds(RESOURCE_ID).secret("123456").and().withClient("clientapp1").authorizedGrantTypes("隐式").scopes("读", "写").autoApprove(true);//@格式化程序:打开}}@配置@EnableResourceServer受保护的静态类 ResourceServerConfiguration 扩展了 ResourceServerConfigurerAdapter {@自动连线私有 ResourceServerTokenServices 令牌服务;@覆盖公共无效配置(ResourceServerSecurityConfigurer 资源){//@格式化程序:关闭资源.resourceId(RESOURCE_ID).tokenServices(tokenService);//@格式化程序:打开}@覆盖公共无效配置(HttpSecurity http)抛出异常{//@格式化程序:关闭http.authorizeRequests().antMatchers("/profile/*").authenticated().and().csrf().disable().sessionManagement().sessionCreationPolicy(STATELESS);//@格式化程序:打开}}}

login.html 页面 Thymeleaf 模板:

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3"><头><title>Spring 安全示例 </title><身体><div th:if="${param.error}">用户名和密码无效.

<div th:if="${param.logout}">您已注销.

<form th:action="@{/login}" method="post"><div><标签>用户名:<input type="text" name="username"/></label></div><div><标签>密码:<input type="password" name="password"/></label></div><div><input type="submit" value="Sign In"/></div></表单></html>

Maven 工件版本:

1.4.0.RELEASE<spring-security-core.version>4.1.3.RELEASE</spring-security-core.version><spring-security-oauth2.version>2.0.11.RELEASE</spring-security-oauth2.version>

现在,当我尝试访问以下网址时:

http://localhost:8080/oauth/authorize?response_type=implicit&client_id=clientapp1

我已成功重定向到位于 http://localhost:8080/login 的登录页面,但是当我输入用户名/密码并按登录"按钮时,出现以下错误:

白标错误页面此应用程序没有明确的/error 映射,因此您将其视为后备.2016 年 9 月 24 日星期六 21:19:44 EEST出现意外错误(type=Method Not Allowed,status=405).不支持请求方法POST"

我做错了什么以及如何解决这个问题?

更新

在调试中我可以看到以下输出:

DispatcherServlet 名为dispatcherServlet",处理 [/login] 的 POST 请求2016-09-25 10:04:43 [http-nio-8080-exec-2] 调试 o.s.w.s.m.m.a.RequestMappingHandlerMapping -查找路径/login 的处理程序方法2016-09-25 10:04:43 [http-nio-8080-exec-2] 调试 o.s.w.s.m.m.a.RequestMappingHandlerMapping -没有找到 [/login] 的处理程序方法2016-09-25 10:04:43 [http-nio-8080-exec-2] 调试 o.s.w.s.h.SimpleUrlHandlerMapping -使用处理程序 [org.springframework.web.servlet.mvc.ParameterizableViewController@c85e70] 和 1 个拦截器将 [/login] 映射到 HandlerExecutionChain2016-09-25 10:04:43 [http-nio-8080-exec-2] 调试 o.s.w.s.m.a.ResponseStatusExceptionResolver -解决处理程序异常 [org.springframework.web.servlet.mvc.ParameterizableViewController@c85e70]:org.springframework.web.HttpRequestMethodNotSupportedException:不支持请求方法POST"2016-09-25 10:04:43 [http-nio-8080-exec-2] 调试 o.s.w.s.m.s.DefaultHandlerExceptionResolver -解决处理程序异常 [org.springframework.web.servlet.mvc.ParameterizableViewController@c85e70]:org.springframework.web.HttpRequestMethodNotSupportedException:不支持请求方法POST"2016-09-25 10:04:43 [http-nio-8080-exec-2] 警告 o.s.web.servlet.PageNotFound -不支持请求方法POST"2016-09-25 10:04:43 [http-nio-8080-exec-2] 调试 o.s.s.w.h.writers.HstsHeaderWriter -不注入 HSTS 标头,因为它与 requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@16580a4 不匹配2016-09-25 10:04:43 [http-nio-8080-exec-2] 调试 os.web.servlet.DispatcherServlet -Null ModelAndView 返回给 DispatcherServlet,名称为dispatcherServlet":假设 HandlerAdapter 已完成请求处理2016-09-25 10:04:43 [http-nio-8080-exec-2] 调试 os.web.servlet.DispatcherServlet -成功完成请求

另外,关于这个问题还有另一个问题没有提供答案使用 oauth2 和 formlogin 未在 Spring Security 中调用 usernamepasswordauthenticationfilter

解决方案

这是我的 ResourceServer 配置错误的问题.

使用以下配置,一切正常:

@Configuration@EnableResourceServer受保护的静态类 ResourceServerConfiguration 扩展了 ResourceServerConfigurerAdapter {@自动连线私有 ResourceServerTokenServices 令牌服务;@覆盖公共无效配置(ResourceServerSecurityConfigurer 资源){//@格式化程序:关闭资源.resourceId(RESOURCE_ID).tokenServices(tokenService);//@格式化程序:打开}@覆盖公共无效配置(HttpSecurity http)抛出异常{//@格式化程序:关闭http.antMatcher("/api/**" ).authorizeRequests().anyRequest().authenticated().and().csrf().disable().sessionManagement().sessionCreationPolicy(STATELESS);//@格式化程序:打开}}

In my Spring Boot application I'm trying to configure OAuth2 implicit flow. For this purpose I'm trying to configure custom login form.

This is my config:

@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("index");
        registry.addViewController("/login").setViewName("login");
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
    }

}

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private SocialAuthenticationSuccessHandler socialAuthenticationSuccessHandler;

    @Autowired
    private DBUserDetailsService userDetailsService;

    @Value("${social.postLogin.url}")
    private String postLoginUrl;

    @Override
    public void configure(WebSecurity web) throws Exception {
        // Spring Security ignores request to static resources such as CSS or JS
        // files.
        web.ignoring().antMatchers("/static/**");
    }


    @Override
    protected void configure(HttpSecurity http) throws Exception {

        // @formatter:off
        http.addFilterBefore(new CorsFilter(), ChannelProcessingFilter.class);

        // Set a custom successHandler on the SocialAuthenticationFilter
        final SpringSocialConfigurer socialConfigurer = new SpringSocialConfigurer();
        socialConfigurer.addObjectPostProcessor(new ObjectPostProcessor<SocialAuthenticationFilter>() {
            @Override
            public <O extends SocialAuthenticationFilter> O postProcess(O socialAuthenticationFilter) {
                socialAuthenticationFilter.setAuthenticationSuccessHandler(socialAuthenticationSuccessHandler);
                socialAuthenticationFilter.setPostLoginUrl(postLoginUrl);
                return socialAuthenticationFilter;
            }
        });

        http
            .csrf().disable()
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
        .and()
            .authorizeRequests()

            .antMatchers("/oauth/authorize").authenticated()
            //Anyone can access the urls
            .antMatchers("/auth/**").permitAll()
            .antMatchers("/actuator/health").permitAll()
            .antMatchers("/actuator/**").hasAuthority("PERMISSION_READ_ACTUATOR_DATA")
            .antMatchers("/login").permitAll()
            .anyRequest().authenticated()
        .and()
            .formLogin()
                .loginPage("/login")
                .loginProcessingUrl("/login")
                .usernameParameter("username")
                .passwordParameter("password")
                .permitAll()
        //Adds the SocialAuthenticationFilter to Spring Security's filter chain.
        .and()
            // apply the configuration from the socialConfigurer (adds the SocialAuthenticationFilter)
            .apply(socialConfigurer);
        // @formatter:on
    }

    /**
     * Configures the authentication manager bean which processes authentication
     * requests.
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
    }

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

}

@Configuration
public class OAuth2ServerConfig {

    private static final String RESOURCE_ID = "restservice";

    @Autowired
    private DBUserDetailsService userDetailsService;

    @Bean
    @Primary
    public DefaultTokenServices tokenServices() {
        DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
        defaultTokenServices.setTokenStore(tokenStore());
        defaultTokenServices.setSupportRefreshToken(true);
        return defaultTokenServices;
    }

    @Bean
    public JwtAccessTokenConverter accessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter() {

            @Override
            public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
                DBUserDetails user = (DBUserDetails) authentication.getUserAuthentication().getPrincipal();
                final Map<String, Object> additionalInfo = new HashMap<>();
                additionalInfo.put("user_id", user.getUser().getId());
                ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
                OAuth2AccessToken enhancedToken = super.enhance(accessToken, authentication);
                return enhancedToken;
            }

        };

        converter.setSigningKey("123");

        DefaultAccessTokenConverter accessTokenConverter = new DefaultAccessTokenConverter();
        DefaultUserAuthenticationConverter userTokenConverter = new DefaultUserAuthenticationConverter();
        userTokenConverter.setUserDetailsService(userDetailsService);
        accessTokenConverter.setUserTokenConverter(userTokenConverter);

        converter.setAccessTokenConverter(accessTokenConverter);

        return converter;
    }

    @Bean
    public TokenStore tokenStore() {
        return new JwtTokenStore(accessTokenConverter());
    }

    @Configuration
    @EnableAuthorizationServer
    protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {

        @Autowired
        @Qualifier("authenticationManagerBean")
        private AuthenticationManager authenticationManager;

        @Autowired
        private TokenStore tokenStore;

        @Autowired
        private TokenEnhancer tokenEnhancer;

        @Override
        public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
            // @formatter:off
            endpoints
                .tokenStore(tokenStore)
                .tokenEnhancer(tokenEnhancer)
                .authenticationManager(this.authenticationManager);
            // @formatter:on
        }

        @Override
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
            // @formatter:off
            clients
                .inMemory()
                    .withClient("clientapp")
                        .authorizedGrantTypes("password","refresh_token")
                        //.authorizedGrantTypes("implicit")
                        .authorities("ROLE_CLIENT")
                        .scopes("read", "write")
                        .resourceIds(RESOURCE_ID)
                        .secret("123456")
                    .and()
                    .withClient("clientapp1")
                        .authorizedGrantTypes("implicit")
                        .scopes("read", "write")
                        .autoApprove(true);
            // @formatter:on
        }

    }

    @Configuration
    @EnableResourceServer
    protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {

        @Autowired
        private ResourceServerTokenServices tokenService;

        @Override
        public void configure(ResourceServerSecurityConfigurer resources) {
            // @formatter:off
            resources           
                .resourceId(RESOURCE_ID)
                .tokenServices(tokenService);
            // @formatter:on
        }

        @Override
        public void configure(HttpSecurity http) throws Exception {
            // @formatter:off
            http
                .authorizeRequests()
                    .antMatchers("/profile/*").authenticated()
                    .and().csrf()
                    .disable().sessionManagement().sessionCreationPolicy(STATELESS);
            // @formatter:on
        }

    }

}

login.html page Thymeleaf template:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
    <head>
        <title>Spring Security Example </title>
    </head>
    <body>
        <div th:if="${param.error}">
            Invalid username and password.
        </div>
        <div th:if="${param.logout}">
            You have been logged out.
        </div>
        <form th:action="@{/login}" method="post">
            <div><label> User Name : <input type="text" name="username"/> </label></div>
            <div><label> Password: <input type="password" name="password"/> </label></div>
            <div><input type="submit" value="Sign In"/></div>
        </form>
    </body>
</html>

Maven artifact versions:

<spring.boot.version>1.4.0.RELEASE</spring.boot.version>
<spring-security-core.version>4.1.3.RELEASE</spring-security-core.version>
<spring-security-oauth2.version>2.0.11.RELEASE</spring-security-oauth2.version>

Right now, when I'm trying to access following url:

http://localhost:8080/oauth/authorize?response_type=implicit&client_id=clientapp1

I'm successfully redirected to my login page at http://localhost:8080/login but when I enter username/password and press "Sign in" button I'm getting following error:

Whitelabel Error Page

This application has no explicit mapping for /error, so you are seeing this as a fallback.
Sat Sep 24 21:19:44 EEST 2016
There was an unexpected error (type=Method Not Allowed, status=405).
Request method 'POST' not supported

What am I doing wrong and how to fix this issue ?

UPDATED

In debug I can see the following output:

DispatcherServlet with name 'dispatcherServlet' processing POST request for [/login]
2016-09-25 10:04:43 [http-nio-8080-exec-2] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping -
                Looking up handler method for path /login
2016-09-25 10:04:43 [http-nio-8080-exec-2] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping -
                Did not find handler method for [/login]
2016-09-25 10:04:43 [http-nio-8080-exec-2] DEBUG o.s.w.s.h.SimpleUrlHandlerMapping -
                Mapping [/login] to HandlerExecutionChain with handler [org.springframework.web.servlet.mvc.ParameterizableViewController@c85e70] and 1 interceptor
2016-09-25 10:04:43 [http-nio-8080-exec-2] DEBUG o.s.w.s.m.a.ResponseStatusExceptionResolver -
                Resolving exception from handler [org.springframework.web.servlet.mvc.ParameterizableViewController@c85e70]: org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' not supported
2016-09-25 10:04:43 [http-nio-8080-exec-2] DEBUG o.s.w.s.m.s.DefaultHandlerExceptionResolver -
                Resolving exception from handler [org.springframework.web.servlet.mvc.ParameterizableViewController@c85e70]: org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' not supported
2016-09-25 10:04:43 [http-nio-8080-exec-2] WARN  o.s.web.servlet.PageNotFound -
                Request method 'POST' not supported
2016-09-25 10:04:43 [http-nio-8080-exec-2] DEBUG o.s.s.w.h.writers.HstsHeaderWriter -
                Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@16580a4
2016-09-25 10:04:43 [http-nio-8080-exec-2] DEBUG o.s.web.servlet.DispatcherServlet -
                Null ModelAndView returned to DispatcherServlet with name 'dispatcherServlet': assuming HandlerAdapter completed request handling
2016-09-25 10:04:43 [http-nio-8080-exec-2] DEBUG o.s.web.servlet.DispatcherServlet -
                Successfully completed request

Also, there is another question about this issue with no answer provided usernamepasswordauthenticationfilter not getting invoked in spring security with oauth2 and formlogin

解决方案

It was my issue with a wrong configuration of ResourceServer.

With a following configuration everything is working fine:

@Configuration
@EnableResourceServer
protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {

    @Autowired
    private ResourceServerTokenServices tokenService;

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) {
        // @formatter:off
        resources           
            .resourceId(RESOURCE_ID)
            .tokenServices(tokenService);
        // @formatter:on
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        // @formatter:off
        http                
            .antMatcher("/api/**" )
            .authorizeRequests().anyRequest().authenticated()
            .and()
                .csrf().disable()
                .sessionManagement().sessionCreationPolicy(STATELESS);
        // @formatter:on
    }

}

这篇关于Spring Boot OAuth2 隐式流 + 表单登录和请求方法“POST"不支持错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
其他开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆