[英]Logging in/out of Spring application using Spring Security and CSRF protection
我正在基于Spring Security Hello World示例构建一个Spring Web应用程序。 我正在尝试通过Spring Security实现登录和注销。 我可以成功登录,但无法注销。 重定向按预期发生,但在注销后尝试加载登录页面时:
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
抛出:
Mar 01, 2016 3:24:01 PM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [laughing-robot] in context with
path [/laughing-robot] threw exception [An exception occurred processing JSP page /WEB-INF/jsp/login.jsp at line 43.
Stacktrace:] with root cause
java.lang.IllegalStateException: Cannot create a session after the response has been committed
at org.apache.catalina.connector.Request.doGetSession(Request.java:2928)
at org.apache.catalina.connector.Request.getSession(Request.java:2298)
这是jsp中的注销表单:
<c:url var="logoutUrl" value="/logout"/>
<form action="${logoutUrl}" method="post">
<input type="submit" value="Logout" />
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
</form>
有人有什么建议吗? 我很乐意提供源文件,但不确定是否相关。
更新:
我一直在尝试通过注释(与xml配置)进行设置。 我不确定这样做的优缺点。 这是我的servlet.xml
:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<mvc:resources mapping="/images/**" location="/images/" />
<mvc:annotation-driven />
<context:component-scan base-package="com.robot.configuration"/>
<mvc:default-servlet-handler/>
<bean name="/" class="com.robot.controllers.HelloController" />
</beans>
我的登录控制器(我认为实际上并没有实现它,请在此处设置多个从未命中的断点。):
@EnableWebMvc
@ComponentScan("com.robot.configuration")
public class LoginController extends WebMvcConfigurerAdapter {
protected final Log logger = LogFactory.getLog(getClass());
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/login").setViewName("login");
registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
}
}
和我的安全配置类:
@Configuration
@EnableWebSecurity
public class RobotSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
RobotLoginSuccessHandler robotLoginSuccessHandler;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/images/**").permitAll()
.anyRequest().authenticated()
.antMatchers("/", "/home").access("hasRole('USER')")
.antMatchers("/admin/**").access("hasRole('ADMIN')")
.and().formLogin().loginPage("/login").successHandler(robotLoginSuccessHandler)
.usernameParameter("username").passwordParameter("password")
.and().csrf()
.and().exceptionHandling().accessDeniedPage("/Access_Denied")
.and()
.formLogin()
.loginPage("/login")
.usernameParameter("username")
.passwordParameter("password")
.permitAll()
.and()
.logout()
.permitAll();
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER")
.and()
.withUser("admin").password("password").roles("ADMIN","USER");
}
最终写了一个实现LogoutSuccessHandler的类。 我完全从库存LogoutSuccessHandler复制了这些方法。 然后,我修改了SecurityConfiguration类以包括注销参数:
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/images/**").permitAll()
.anyRequest().authenticated()
.antMatchers("/", "/home").access("hasRole('USER')")
.antMatchers("/admin/**").access("hasRole('ADMIN')")
.and().formLogin().loginPage("/login").successHandler(robotLoginSuccessHandler)
.usernameParameter("username").passwordParameter("password")
.and().exceptionHandling().accessDeniedPage("/Access_Denied")
.and()
.formLogin()
.loginPage("/login")
.usernameParameter("username")
.passwordParameter("password")
.permitAll()
.and()
.logout()
.and().logout().logoutUrl("/login?logout").addLogoutHandler(robotLogoutSuccessHandler)
.permitAll();
}
我猜想因为定义了自己的配置类,所以我需要指定要LogoutHandler执行的确切位置。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.