HTTP状态405 - 不支持请求方法'POST' - Spring Security

Posted

技术标签:

【中文标题】HTTP状态405 - 不支持请求方法\'POST\' - Spring Security【英文标题】:HTTP Status 405 - Request method 'POST' not supported - Spring SecurityHTTP状态405 - 不支持请求方法'POST' - Spring Security 【发布时间】:2015-05-01 15:44:20 【问题描述】:

当我尝试实现 Spring 安全性时出现以下错误 -

控制器:

@Controller
public class EmployeeController 

    @RequestMapping(value =  "/", "/welcome**" , method = RequestMethod.GET)
    public ModelAndView defaultPage() 

        ModelAndView model = new ModelAndView();
        model.addObject("title", "Spring Security + Hibernate Example");
        model.addObject("message", "This is default page!");
        model.setViewName("hello");
        return model;
    

    @RequestMapping(value = "/admin**", method = RequestMethod.GET)
    public ModelAndView adminPage() 

        ModelAndView model = new ModelAndView();
        model.addObject("title", "Spring Security + Hibernate Example");
        model.addObject("message", "This page is for ROLE_ADMIN only!");
        model.setViewName("admin");

        return model;
    

    @RequestMapping(value = "/login", method = RequestMethod.GET)
    public ModelAndView login(
            @RequestParam(value = "error", required = false) String error,
            @RequestParam(value = "logout", required = false) String logout,
            HttpServletRequest request) 

        ModelAndView model = new ModelAndView();
        if (error != null) 
            model.addObject("error",
                    getErrorMessage(request, "SPRING_SECURITY_LAST_EXCEPTION"));
        

        if (logout != null) 
            model.addObject("msg", "You've been logged out successfully.");
        
        model.setViewName("login");

        return model;
    

    // customize the error message
    private String getErrorMessage(HttpServletRequest request, String key) 

        Exception exception = (Exception) request.getSession()
                .getAttribute(key);

        String error = "";
        if (exception instanceof BadCredentialsException) 
            error = "Invalid username and password!";
         else if (exception instanceof LockedException) 
            error = exception.getMessage();
         else 
            error = "Invalid username and password!";
        
        return error;
    

    // for 403 access denied page
    @RequestMapping(value = "/403", method = RequestMethod.GET)
    public ModelAndView accesssDenied() 

        ModelAndView model = new ModelAndView();

        // check if user is login
        Authentication auth = SecurityContextHolder.getContext()
                .getAuthentication();
        if (!(auth instanceof AnonymousAuthenticationToken)) 
            UserDetails userDetail = (UserDetails) auth.getPrincipal();
            System.out.println(userDetail);

            model.addObject("username", userDetail.getUsername());
        

        model.setViewName("403");
        return model;
    

web.xml

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
    <display-name>Archetype Created Web Application</display-name>
    <servlet>
        <servlet-name>mvc-dispatcher</servlet-name>
        <servlet-class>
            org.springframework.web.servlet.DispatcherServlet
        </servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>mvc-dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <listener>
        <listener-class>
            org.springframework.web.context.ContextLoaderListener
        </listener-class>
    </listener>
    
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/mvc-dispatcher-servlet.xml,
            /WEB-INF/spring-security.xml
        </param-value>
    </context-param>
    <!-- /WEB-INF/spring-security.xml -->

    <!-- Spring Security -->
    <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

Spring-security.xml

<beans:beans xmlns="http://www.springframework.org/schema/security"
    xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/security
    http://www.springframework.org/schema/security/spring-security-3.2.xsd">

    <!-- enable use-expressions -->
    <http auto-config="true" use-expressions="true">
        <intercept-url pattern="/admin**" access="hasRole('ROLE_ADMIN')" />

        <!-- access denied page -->
        <access-denied-handler error-page="/403" />
        <form-login 
            login-page="/login" 
            default-target-url="/welcome"
            authentication-failure-url="/login?error" 
            username-parameter="username"
            password-parameter="password" />
        <logout logout-success-url="/login?logout" />
        <!-- enable csrf protection -->
        <csrf />
    </http>

    <authentication-manager>
        <authentication-provider user-service-ref="myUserDetailsService" >
            <password-encoder hash="bcrypt" />    
        </authentication-provider>
    </authentication-manager>

</beans:beans>

login.jsp

<body onload='document.loginForm.username.focus();'>

    <h1>Spring Security Login Form (Database + Hibernate Authentication)</h1>

    <div id="login-box">

        <h3>Login with Username and Password</h3>

        <c:if test="$not empty error">
            <div class="error">$error</div>
        </c:if>
        <c:if test="$not empty msg">
            <div class="msg">$msg</div>
        </c:if>

        <form name='loginForm'
            action="<c:url value='/j_spring_security_check' />" method='POST'>

            <table>
                <tr>
                    <td>User:</td>
                    <td><input type='text' name='username'></td>
                </tr>
                <tr>
                    <td>Password:</td>
                    <td><input type='password' name='password' /></td>
                </tr>
                <tr>
                    <td colspan='2'><input name="submit" type="submit"
                        value="submit" /></td>
                </tr>
            </table>

            <input type="hidden" name="$_csrf.parameterName"
                value="$_csrf.token" />

        </form>
    </div>

</body>

错误:-

http://localhost:8080/EmployeeManagement/j_spring_security_check

09:01:22.135 [http-8080-4] DEBUG o.s.s.web.DefaultRedirectStrategy - Redirecting to 'http://localhost:8080/EmployeeManagement/login;jsessionid=E27C22793BAA2C7FC38039260EC08152'
    09:01:22.135 [http-8080-4] DEBUG o.s.s.w.c.HttpSessionSecurityContextRepository - SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
    09:01:22.136 [http-8080-4] DEBUG o.s.s.w.c.SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as request processing completed
    09:01:22.145 [http-8080-4] DEBUG o.s.security.web.FilterChainProxy - /login at position 1 of 11 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
    09:01:22.145 [http-8080-4] DEBUG o.s.s.w.c.HttpSessionSecurityContextRepository - HttpSession returned null object for SPRING_SECURITY_CONTEXT
    09:01:22.145 [http-8080-4] DEBUG o.s.s.w.c.HttpSessionSecurityContextRepository - No SecurityContext was available from the HttpSession: org.apache.catalina.session.StandardSessionFacade@48842f5e. A new one will be created.
    09:01:22.145 [http-8080-4] DEBUG o.s.security.web.FilterChainProxy - /login at position 2 of 11 in additional filter chain; firing Filter: 'CsrfFilter'
    09:01:22.146 [http-8080-4] DEBUG o.s.security.web.FilterChainProxy - /login at position 3 of 11 in additional filter chain; firing Filter: 'LogoutFilter'
    09:01:22.146 [http-8080-4] DEBUG o.s.s.w.u.m.AntPathRequestMatcher - Request 'GET /login' doesn't match 'POST /j_spring_security_logout
    09:01:22.146 [http-8080-4] DEBUG o.s.security.web.FilterChainProxy - /login at position 4 of 11 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
    09:01:22.146 [http-8080-4] DEBUG o.s.security.web.FilterChainProxy - /login at position 5 of 11 in additional filter chain; firing Filter: 'BasicAuthenticationFilter'
    09:01:22.146 [http-8080-4] DEBUG o.s.security.web.FilterChainProxy - /login at position 6 of 11 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
    09:01:22.146 [http-8080-4] DEBUG o.s.s.w.s.DefaultSavedRequest - pathInfo: both null (property equals)
    09:01:22.147 [http-8080-4] DEBUG o.s.s.w.s.DefaultSavedRequest - queryString: both null (property equals)
    09:01:22.147 [http-8080-4] DEBUG o.s.s.w.s.DefaultSavedRequest - requestURI: arg1=/EmployeeManagement/admin; arg2=/EmployeeManagement/login;jsessionid=E27C22793BAA2C7FC38039260EC08152 (property not equals)
    09:01:22.147 [http-8080-4] DEBUG o.s.s.w.s.HttpSessionRequestCache - saved request doesn't match
    09:01:22.147 [http-8080-4] DEBUG o.s.security.web.FilterChainProxy - /login at position 7 of 11 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
    09:01:22.147 [http-8080-4] DEBUG o.s.security.web.FilterChainProxy - /login at position 8 of 11 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
    09:01:22.147 [http-8080-4] DEBUG o.s.s.w.a.AnonymousAuthenticationFilter - Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken@6fa90ed4: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@fffc7f0c: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: E27C22793BAA2C7FC38039260EC08152; Granted Authorities: ROLE_ANONYMOUS'
    09:01:22.147 [http-8080-4] DEBUG o.s.security.web.FilterChainProxy - /login at position 9 of 11 in additional filter chain; firing Filter: 'SessionManagementFilter'
    09:01:22.148 [http-8080-4] DEBUG o.s.security.web.FilterChainProxy - /login at position 10 of 11 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
    09:01:22.148 [http-8080-4] DEBUG o.s.security.web.FilterChainProxy - /login at position 11 of 11 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
    09:01:22.148 [http-8080-4] DEBUG o.s.s.w.u.m.AntPathRequestMatcher - Checking match of request : '/login'; against '/admin**'
    09:01:22.148 [http-8080-4] DEBUG o.s.s.w.a.i.FilterSecurityInterceptor - Public object - authentication not attempted
    09:01:22.148 [http-8080-4] DEBUG o.s.security.web.FilterChainProxy - /login reached end of additional filter chain; proceeding with original chain
    09:01:22.148 [http-8080-4] DEBUG o.s.web.servlet.DispatcherServlet - DispatcherServlet with name 'mvc-dispatcher' processing GET request for [/EmployeeManagement/login]
    09:01:22.149 [http-8080-4] DEBUG o.s.w.s.m.a.DefaultAnnotationHandlerMapping - Mapping [/login] to HandlerExecutionChain with handler [com.employeemgmt.controller.EmployeeController@18ba5047] and 1 interceptor
    09:01:22.150 [http-8080-4] DEBUG o.s.web.servlet.DispatcherServlet - Last-Modified value for [/EmployeeManagement/login] is: -1
    09:01:22.189 [http-8080-4] DEBUG o.s.w.b.a.s.HandlerMethodInvoker - Invoking request handler method: public org.springframework.web.servlet.ModelAndView com.employeemgmt.controller.EmployeeController.login(java.lang.String,java.lang.String,javax.servlet.http.HttpServletRequest)
    09:01:22.190 [http-8080-4] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Invoking afterPropertiesSet() on bean with name 'login'
    09:01:22.190 [http-8080-4] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.transaction.config.internalTransactionAdvisor'
    09:01:22.190 [http-8080-4] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0'
    09:01:22.190 [http-8080-4] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.transaction.config.internalTransactionAdvisor'
    09:01:22.190 [http-8080-4] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0'
    09:01:22.190 [http-8080-4] DEBUG o.s.web.servlet.DispatcherServlet - Rendering view [org.springframework.web.servlet.view.JstlView: name 'login'; URL [/WEB-INF/pages/login.jsp]] in DispatcherServlet with name 'mvc-dispatcher'
    09:01:22.190 [http-8080-4] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'requestDataValueProcessor'
    09:01:22.190 [http-8080-4] DEBUG o.s.web.servlet.view.JstlView - Forwarding to resource [/WEB-INF/pages/login.jsp] in InternalResourceView 'login'
    09:01:22.279 [http-8080-4] DEBUG o.s.s.w.c.HttpSessionSecurityContextRepository - SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
    09:01:22.279 [http-8080-4] DEBUG o.s.web.servlet.DispatcherServlet - Successfully completed request
    09:01:22.279 [http-8080-4] DEBUG o.s.s.w.a.ExceptionTranslationFilter - Chain processed normally
    09:01:22.280 [http-8080-4] DEBUG o.s.s.w.c.SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as request processing completed
    09:01:23.967 [http-8080-4] DEBUG o.s.security.web.FilterChainProxy - /j_spring_security_check at position 1 of 11 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
    09:01:23.967 [http-8080-4] DEBUG o.s.s.w.c.HttpSessionSecurityContextRepository - HttpSession returned null object for SPRING_SECURITY_CONTEXT
    09:01:23.968 [http-8080-4] DEBUG o.s.s.w.c.HttpSessionSecurityContextRepository - No SecurityContext was available from the HttpSession: org.apache.catalina.session.StandardSessionFacade@48842f5e. A new one will be created.
    09:01:23.968 [http-8080-4] DEBUG o.s.security.web.FilterChainProxy - /j_spring_security_check at position 2 of 11 in additional filter chain; firing Filter: 'CsrfFilter'
    09:01:23.969 [http-8080-4] DEBUG o.s.security.web.csrf.CsrfFilter - Invalid CSRF token found for http://localhost:8080/EmployeeManagement/j_spring_security_check
    09:01:23.971 [http-8080-4] DEBUG o.s.web.servlet.DispatcherServlet - DispatcherServlet with name 'mvc-dispatcher' processing POST request for [/EmployeeManagement/403]
    09:01:23.971 [http-8080-4] DEBUG o.s.w.s.m.a.DefaultAnnotationHandlerMapping - Mapping [/403] to HandlerExecutionChain with handler [com.employeemgmt.controller.EmployeeController@18ba5047] and 1 interceptor
    09:01:23.982 [http-8080-4] DEBUG o.s.w.s.m.a.AnnotationMethodHandlerExceptionResolver - Resolving exception from handler [com.employeemgmt.controller.EmployeeController@18ba5047]: org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' not supported
    09:01:23.984 [http-8080-4] DEBUG o.s.w.s.m.a.ResponseStatusExceptionResolver - Resolving exception from handler [com.employeemgmt.controller.EmployeeController@18ba5047]: org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' not supported
    09:01:23.984 [http-8080-4] DEBUG o.s.w.s.m.s.DefaultHandlerExceptionResolver - Resolving exception from handler [com.employeemgmt.controller.EmployeeController@18ba5047]: org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' not supported
    09:01:23.984 [http-8080-4] WARN  o.s.web.servlet.PageNotFound - Request method 'POST' not supported
    09:01:23.984 [http-8080-4] DEBUG o.s.s.w.c.HttpSessionSecurityContextRepository - SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
    09:01:23.984 [http-8080-4] DEBUG o.s.web.servlet.DispatcherServlet - Null ModelAndView returned to DispatcherServlet with name 'mvc-dispatcher': assuming HandlerAdapter completed request handling
    09:01:23.984 [http-8080-4] DEBUG o.s.web.servlet.DispatcherServlet - Successfully completed request
    09:01:23.984 [http-8080-4] DEBUG o.s.s.w.c.HttpSessionSecurityContextRepository - SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
    09:01:23.984 [http-8080-4] DEBUG o.s.s.w.c.SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as request processing completed

【问题讨论】:

此问题已解决。 csrf 标记值没有被替换。一旦我添加 - 它得到了解决 你能把这个作为答案发布吗? 【参考方案1】:

您在控制器中的/login 映射上使用GET 方法。

使用POST方法进行认证是标准的。

@RequestMapping(value = "/login", method = RequestMethod.GET) 更改为 @RequestMapping(value = "/login", method = RequestMethod.POST)

【讨论】:

【参考方案2】:

我在此处添加 OP 找到的答案。

csrf 标记值没有被替换。一旦我添加 - &lt;%@ page isELIgnored ="false" %&gt;

我个人通过删除 spring-security 中的 csrf 解决了这个问题。在http标签集&lt;csrf disabled="true"/&gt;

【讨论】:

【参考方案3】:

您的控制器方法使用 RequestMethod.GET 注释,而 login.jsp 表单方法正在请求 POST。两者都应该是 POST。

【讨论】:

以上是关于HTTP状态405 - 不支持请求方法'POST' - Spring Security的主要内容,如果未能解决你的问题,请参考以下文章

org.springframework.web.servlet.PageNotFound - 请求方法'POST'不支持http状态405

HTTP 状态 405 - 不支持请求方法“POST”(Spring MVC)

WebApi Post 方法总是返回“请求的资源不支持 http 方法 'GET'。”状态:405 方法不允许

SpringMVC HTTP 状态 405 - 不支持请求方法“POST”

Spring:状态 405。不支持请求方法“POST”

Spring Boot POST 请求返回 http 状态 405“方法不允许”而不是 HTTP 状态 404