Thi*_*ago 5 spring spring-mvc spring-security
我有一个sprinc核心+ spring mvc +安全启动并运行,使用XML配置,这些是我目前在我的pom.xml中使用的版本:
<spring.version>4.0.1.RELEASE</spring.version>
<spring.security.version>3.2.0.RELEASE</spring.security.version>
Run Code Online (Sandbox Code Playgroud)
所以我决定继续将我的所有xml配置移动到基于java的配置.会发生什么是Spring安全的login-processing-url停止工作,现在给我一个错误405,说不允许POST.例如,这是我的spring security xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:p="http://www.springframework.org/schema/p"
xmlns="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd">
<!-- Satic content -->
<http pattern="/assets/**" security="none" />
<http pattern="/css/**" security="none" />
<http pattern="/img/**" security="none" />
<http pattern="/js/**" security="none" />
<!--http://docs.spring.io/spring-security/site/docs/3.2.0.RELEASE/reference/htmlsingle/#ns-global-method-->
<global-method-security pre-post-annotations="enabled" />
<!-- Protected Requests -->
<http auto-config="true" use-expressions="true" authentication-manager-ref="authenticationManager">
<intercept-url pattern="/login/**" access="permitAll" />
<intercept-url pattern="/api/**" access="permitAll" />
<intercept-url pattern="/**" access="isRememberMe() or isFullyAuthenticated()" />
<form-login login-processing-url="/loginCheck"
login-page="/login"
authentication-failure-url="/loginFailure"
default-target-url="/"
always-use-default-target="true"
password-parameter="password"
username-parameter="username"/>
<logout delete-cookies="JSESSIONID" logout-url="/logout" logout-success-url="/login" />
<access-denied-handler error-page="/403" />
<session-management invalid-session-url="/login" session-fixation-protection="newSession" />
<headers>
<frame-options/>
<xss-protection/>
</headers>
<remember-me services-ref="rememberMeServices" />
</http>
<authentication-manager alias="authenticationManager">
<authentication-provider ref="mongoDashAuthenticationProvider" />
<authentication-provider ref="rememberMeAuthenticationProvider" />
</authentication-manager>
<beans:bean id="rememberMeServices" class="org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices">
<beans:constructor-arg value="${security.app.key}" />
<beans:constructor-arg ref="userServiceImpl" />
<beans:constructor-arg ref="mongoDashPersistentTokenRepository" />
<beans:property name="tokenValiditySeconds" value="172800" />
<beans:property name="parameter" value="remember" />
<beans:property name="cookieName" value="REMEMBER_ME" />
</beans:bean>
<beans:bean id="rememberMeAuthenticationProvider" class="org.springframework.security.authentication.RememberMeAuthenticationProvider" >
<beans:property name="key" value="${security.app.key}" />
</beans:bean>
<!-- Way better than SHA -->
<beans:bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder">
<beans:constructor-arg name="strength" value="15" />
</beans:bean>
Run Code Online (Sandbox Code Playgroud)
这是我的spring安全性配置文件:
@Configuration
@EnableWebMvcSecurity
@PropertySource("classpath:app.properties")
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Value("${security.app.key}")
String appKey;
@Autowired
UserService userService;
@Autowired
MongoDashPersistentTokenRepository mongoDashPersistentTokenRepository;
@Autowired
public void registerGlobalAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth
.eraseCredentials(true)
.authenticationProvider(new MongoDashAuthenticationProvider())
.authenticationProvider(rememberMeAuthenticationProvider());
//.build();
/**
<authentication-manager alias="authenticationManager">
<authentication-provider ref="mongoDashAuthenticationProvider" />
<authentication-provider ref="rememberMeAuthenticationProvider" />
</authentication-manager>
*/
}
@Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/assets/**")
.antMatchers("/css/**")
.antMatchers("/img/**")
.antMatchers("/js/**")
.antMatchers("/fonts/**");
/**
<http pattern="/assets/**" security="none" />
<http pattern="" security="none" />
<http pattern="" security="none" />
<http pattern="" security="none" />
**/
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.headers()
.xssProtection()
.frameOptions()
.and()
.authorizeRequests()
.antMatchers("/login/**").permitAll()
.antMatchers("/api/**").permitAll()
.antMatchers("/**").access("isRememberMe() or isFullyAuthenticated()")
.and()
.formLogin()
.loginProcessingUrl("/loginCheck")
.loginPage("/login")
//.failureUrl("/loginFailure")
.defaultSuccessUrl("/", true)
.passwordParameter("password")
.usernameParameter("username")
.permitAll()
.and()
.logout()
.logoutSuccessUrl("/login")
.logoutUrl("/logout")
.deleteCookies("JSESSIONID")
.and()
.sessionManagement()
.invalidSessionUrl("/login")
.sessionFixation().newSession()
.and()
.exceptionHandling()
.accessDeniedPage("/403")
.and()
.rememberMe()
.rememberMeServices(rememberMeServices());
}
@Bean
public RememberMeAuthenticationProvider rememberMeAuthenticationProvider() {
RememberMeAuthenticationProvider provider = new RememberMeAuthenticationProvider(appKey);
return provider;
/**
<beans:bean id="rememberMeAuthenticationProvider" class="org.springframework.security.authentication.RememberMeAuthenticationProvider" >
<beans:property name="key" value="${security.app.key}" />
</beans:bean>
**/
}
@Bean
public PersistentTokenBasedRememberMeServices rememberMeServices() {
PersistentTokenBasedRememberMeServices rememberMeServices = new PersistentTokenBasedRememberMeServices(appKey, userService,
mongoDashPersistentTokenRepository);
rememberMeServices.setCookieName("REMEMBER_ME");
rememberMeServices.setParameter("remember");
rememberMeServices.setTokenValiditySeconds(172800);
return rememberMeServices;
/**
<beans:bean id="rememberMeServices" class="org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices">
<beans:constructor-arg value="${security.app.key}" />
<beans:constructor-arg ref="userServiceImpl" />
<beans:constructor-arg ref="mongoDashPersistentTokenRepository" />
<beans:property name="tokenValiditySeconds" value="172800" />
<beans:property name="parameter" value="remember" />
<beans:property name="cookieName" value="REMEMBER_ME" />
</beans:bean>
**/
}
@Bean
public BCryptPasswordEncoder passwordEncoder() {
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(15);
return passwordEncoder;
/**
<beans:bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder">
<beans:constructor-arg name="strength" value="15" />
</beans:bean>
**/
}
}
Run Code Online (Sandbox Code Playgroud)
这是我的AppConfig
@Configuration
@Import({SecurityConfig.class})
//@ImportResource("classpath:spring/security-context.xml")
@ComponentScan(basePackages = { "com.mongom" }, excludeFilters = { @ComponentScan.Filter(Controller.class),
@ComponentScan.Filter(Configuration.class) })
@PropertySource(value = { "classpath:app.properties" })
@EnableMBeanExport
@EnableAspectJAutoProxy
public class AppConfig {
@Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasenames("validation", "messages");
return messageSource;
}
@Bean
public PropertiesFactoryBean properties() {
PropertiesFactoryBean ppc = new PropertiesFactoryBean();
ppc.setLocations(new Resource[] { new ClassPathResource("app.properties") });
ppc.setIgnoreResourceNotFound(false);
return ppc;
}
}
Run Code Online (Sandbox Code Playgroud)
web.xml中
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<display-name>MongoDASH</display-name>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>com.mongom.spring.AppConfig</param-value>
</context-param>
<servlet>
<servlet-name>mongodash</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</init-param>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>com.mongom.spring.WebConfig</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mongodash</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 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>
<env-entry>
<description>JNDI logging context for this app</description>
<env-entry-name>logback/contextName</env-entry-name>
<env-entry-type>java.lang.String</env-entry-type>
<env-entry-value>mongom</env-entry-value>
</env-entry>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<error-page>
<error-code>400</error-code>
<location>/404</location>
</error-page>
<error-page>
<error-code>404</error-code>
<location>/404</location>
</error-page>
<error-page>
<error-code>403</error-code>
<location>/403</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/500</location>
</error-page>
Run Code Online (Sandbox Code Playgroud)
控制台输出:
02/06 11:53:26.678 [http-bio-8080-exec-7] WARN o.s.web.servlet.PageNotFound Request method 'POST' not supported
02/06 11:53:50.023 [http-bio-8080-exec-5] WARN o.s.web.servlet.PageNotFound Request method 'POST' not supported
02/06 11:53:53.408 [http-bio-8080-exec-5] WARN o.s.web.servlet.PageNotFound Request method 'POST' not supported
02/06 11:53:55.504 [http-bio-8080-exec-5] WARN o.s.web.servlet.PageNotFound Request method 'POST' not supported
Run Code Online (Sandbox Code Playgroud)
登录表格:
<form class="form-signin" action="loginCheck" method="POST">
<h2 class="form-signin-heading">sign in now</h2>
<div class="login-wrap">
<input type="text" name="username" class="form-control" placeholder="User ID" autofocus value="guest" />
<input type="password" name="password" class="form-control" placeholder="Password" value="!Guest2014!" />
<label class="checkbox">
<input type="checkbox" name="remember" />Remember me
<span class="pull-right">
<a data-toggle="modal" href="#myModal"> Forgot Password?</a>
</span>
</label>
<button class="btn btn-lg btn-login btn-block" type="submit">Sign in</button>
</div>
</form>
Run Code Online (Sandbox Code Playgroud)
Spring安全日志:
02/06 15:57:34.202 [localhost-startStop-1] INFO o.s.s.web.DefaultSecurityFilterChain Creating filter chain: Ant [pattern='/assets/**'], []
02/06 15:57:34.202 [localhost-startStop-1] INFO o.s.s.web.DefaultSecurityFilterChain Creating filter chain: Ant [pattern='/css/**'], []
02/06 15:57:34.203 [localhost-startStop-1] INFO o.s.s.web.DefaultSecurityFilterChain Creating filter chain: Ant [pattern='/img/**'], []
02/06 15:57:34.203 [localhost-startStop-1] INFO o.s.s.web.DefaultSecurityFilterChain Creating filter chain: Ant [pattern='/js/**'], []
02/06 15:57:34.203 [localhost-startStop-1] INFO o.s.s.web.DefaultSecurityFilterChain Creating filter chain: Ant [pattern='/fonts/**'], []
02/06 15:57:34.264 [localhost-startStop-1] INFO o.s.s.web.DefaultSecurityFilterChain Creating filter chain: org.springframework.security.web.util.matcher.AnyRequestMatcher@1, [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@28562791, org.springframework.security.web.context.SecurityContextPersistenceFilter@1f33b16a, org.springframework.security.web.header.HeaderWriterFilter@12504e0, org.springframework.security.web.csrf.CsrfFilter@7ff12373, org.springframework.security.web.authentication.logout.LogoutFilter@40e9e799, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@334362d9, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@892b7c2, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@d0da1d8, org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter@5eba06ff, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@303fb547, org.springframework.security.web.session.SessionManagementFilter@a5ae1e7, org.springframework.security.web.access.ExceptionTranslationFilter@13883d5f, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@52ecba8]
Run Code Online (Sandbox Code Playgroud)
发布登录表单时Spring安全性很长:
02/06 17:04:33.642 [http-bio-8080-exec-10] DEBUG o.s.s.w.u.m.AntPathRequestMatcher Checking match of request : '/logincheck'; against '/assets/**'
02/06 17:04:33.643 [http-bio-8080-exec-10] DEBUG o.s.s.w.u.m.AntPathRequestMatcher Checking match of request : '/logincheck'; against '/css/**'
02/06 17:04:33.644 [http-bio-8080-exec-10] DEBUG o.s.s.w.u.m.AntPathRequestMatcher Checking match of request : '/logincheck'; against '/img/**'
02/06 17:04:33.644 [http-bio-8080-exec-10] DEBUG o.s.s.w.u.m.AntPathRequestMatcher Checking match of request : '/logincheck'; against '/js/**'
02/06 17:04:33.645 [http-bio-8080-exec-10] DEBUG o.s.s.w.u.m.AntPathRequestMatcher Checking match of request : '/logincheck'; against '/fonts/**'
02/06 17:04:33.645 [http-bio-8080-exec-10] DEBUG o.s.security.web.FilterChainProxy /loginCheck at position 1 of 13 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
02/06 17:04:33.645 [http-bio-8080-exec-10] DEBUG o.s.security.web.FilterChainProxy /loginCheck at position 2 of 13 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
02/06 17:04:33.646 [http-bio-8080-exec-10] DEBUG o.s.s.w.c.HttpSessionSecurityContextRepository HttpSession returned null object for SPRING_SECURITY_CONTEXT
02/06 17:04:33.700 [http-bio-8080-exec-10] DEBUG o.s.s.w.c.HttpSessionSecurityContextRepository No SecurityContext was available from the HttpSession: org.apache.catalina.session.StandardSessionFacade@705ebc6e. A new one will be created.
02/06 17:04:33.701 [http-bio-8080-exec-10] DEBUG o.s.security.web.FilterChainProxy /loginCheck at position 3 of 13 in additional filter chain; firing Filter: 'HeaderWriterFilter'
02/06 17:04:33.701 [http-bio-8080-exec-10] DEBUG o.s.security.web.FilterChainProxy /loginCheck at position 4 of 13 in additional filter chain; firing Filter: 'CsrfFilter'
02/06 17:04:33.702 [http-bio-8080-exec-10] DEBUG o.s.security.web.csrf.CsrfFilter Invalid CSRF token found for http://localhost:8080/mongodash/loginCheck
02/06 17:04:33.703 [http-bio-8080-exec-10] DEBUG o.s.web.servlet.DispatcherServlet DispatcherServlet with name 'mongodash' processing POST request for [/mongodash/403]
02/06 17:04:33.704 [http-bio-8080-exec-10] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping Looking up handler method for path /403
02/06 17:04:33.719 [http-bio-8080-exec-10] DEBUG o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver Resolving exception from handler [null]: org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' not supported
02/06 17:04:33.719 [http-bio-8080-exec-10] DEBUG o.s.w.s.m.a.ResponseStatusExceptionResolver Resolving exception from handler [null]: org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' not supported
02/06 17:04:33.720 [http-bio-8080-exec-10] DEBUG o.s.w.s.m.s.DefaultHandlerExceptionResolver Resolving exception from handler [null]: org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' not supported
02/06 17:04:33.720 [http-bio-8080-exec-10] WARN o.s.web.servlet.PageNotFound Request method 'POST' not supported
02/06 17:04:33.721 [http-bio-8080-exec-10] DEBUG o.s.s.w.c.HttpSessionSecurityContextRepository SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
02/06 17:04:33.721 [http-bio-8080-exec-10] DEBUG o.s.web.servlet.DispatcherServlet Null ModelAndView returned to DispatcherServlet with name 'mongodash': assuming HandlerAdapter completed request handling
02/06 17:04:33.721 [http-bio-8080-exec-10] DEBUG o.s.web.servlet.DispatcherServlet Successfully completed request
02/06 17:04:33.722 [http-bio-8080-exec-10] DEBUG o.s.s.w.c.HttpSessionSecurityContextRepository SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
02/06 17:04:33.722 [http-bio-8080-exec-10] DEBUG o.s.s.w.c.SecurityContextPersistenceFilter SecurityContextHolder now cleared, as request processing completed
Run Code Online (Sandbox Code Playgroud)
我的问题是:我在这里错过了什么吗?我看到应用程序工作正常,因为我可以看到登录页面和资源(js,css,img)显示在该页面上,它只是login-processing-url,当通过POST通过登录表单调用时,它不起作用.
谢谢TL
编辑#1:使用登录表单和spring安全日志进行更新
编辑#2:在发布登录信息时使用spring安全日志进行更新
根据您发布的日志,问题似乎是您没有在登录请求中包含CSRF令牌.
DEBUG o.s.security.web.csrf.CsrfFilter Invalid CSRF token found for http://localhost:8080/mongodash/loginCheck
Run Code Online (Sandbox Code Playgroud)
基于XML的配置不会发生这种情况,因为默认情况下,CSRF未启用XML配置(被动).由于登录请求中没有CSRF令牌,因此Spring Security将转发到/ 403错误页面(这是在Java Config中配置为拒绝访问页面的内容).似乎处理/ 403的MVC控制器不允许HTTP POST并记录您看到的错误消息.
要解决这个问题,首先我要确保/ 403可以处理其他方法.这将有助于解决您可能遇到的任何其他类似问题(即,此时您应该获得正确的错误消息,而不是看到不支持该方法的错误).
其次,你有一个选择:
在所有POST,PUT,DELETE等表单中包含CSRF令牌.这将确保您免受CSRF攻击.
更新:如果您正在使用@EnableWebMvcSecuritySpring的JSP标记库或Thymeleaf 2.1+来呈现表单,那么将自动包含CSRF令牌.有关自动包含的详细信息以及如何手动包含令牌的示例,请参阅参考的" 包括CSRF令牌"部分.
或者,您可以禁用CSRF保护.不建议这样做,但如果要升级到Spring Security的Java配置,可以帮助缩小差距.
您可以在参考文献的CSRF部分中阅读有关CSRF保护的更多信息.
一些额外的项目:
您是否有明确配置标头的原因?您指定的配置会禁用一些有助于保护您的应用程序的默认标头.显式配置不包括缓存控制头.
更新:例如,您有以下内容:
http
.headers()
.xssProtection()
.frameOptions()
.and()
.authorizeRequests()
Run Code Online (Sandbox Code Playgroud)
如果您只是删除标头声明,则默认情况下会添加所有默认标头.
http
.authorizeRequests()
Run Code Online (Sandbox Code Playgroud)
对于XML配置,您可以包含<headers/>没有子项的元素来获取所有默认标头.这种显式的XML设置对于保持被动是必要的.
有关标头的更多信息,请参阅参考资料的" 安全HTTP响应标头"部分.
您可以安全地从代码中删除相当多的配置,因为Java配置将默认为这些值.例如,用户名和密码参数配置是不必要的,因为这是默认值.
| 归档时间: |
|
| 查看次数: |
10138 次 |
| 最近记录: |