繁体   English   中英

使用Spring Security和CSRF保护登录/注销Spring应用程序

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM