logoutSuccessUrl无法在Spring Boot中工作

时间:2016-03-04 04:05:10

标签: security spring-boot

我有一个简单的Gradle Spring Boot(v 1.3.3)WebMVC应用程序我通过“Gradle bootrun”从命令行运行。我还包括Spring Security,并通过包含java安全配置类来覆盖一些默认的安全配置。我的构建文件是

buildscript {
    ext {
        springBootVersion = '1.3.3.RELEASE'
    }
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") 
    }
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'spring-boot' 

jar {
    baseName = 'readinglist'
    version = '0.0.1-SNAPSHOT'
}
sourceCompatibility = 1.8
targetCompatibility = 1.8

repositories {
    mavenCentral()
}

dependencies {
    compile('org.springframework.boot:spring-boot-starter-data-jpa')
    compile('org.springframework.boot:spring-boot-starter-thymeleaf')
    compile('org.springframework.boot:spring-boot-starter-web')
    compile("org.springframework.boot:spring-boot-starter-security")
    runtime('com.h2database:h2')
    testCompile('org.springframework.boot:spring-boot-starter-test') 
}

eclipse {
    classpath {
         containers.remove('org.eclipse.jdt.launching.JRE_CONTAINER')
         containers 'org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8'
    }
}

task wrapper(type: Wrapper) {
    gradleVersion = '2.9'
}

我的安全配置类是

package readinglist;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

  @Autowired
  private ReaderRepository readerRepository;

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http
      .authorizeRequests()
        .antMatchers("/readingList").access("hasRole('READER')")
        .antMatchers("/**").permitAll()
      .and()
      .formLogin()
        .loginPage("/login")
        .failureUrl("/login?error=true")
      .and()
        .logout()
           .logoutSuccessUrl("/");  // Added .and()....logoutSuccessURL()
  }

  @Override
  protected void configure(
              AuthenticationManagerBuilder auth) throws Exception {
    auth
      .userDetailsService(new UserDetailsService() {
        @Override
        public UserDetails loadUserByUsername(String username)
            throws UsernameNotFoundException {
          UserDetails userDetails = readerRepository.findOne(username);
          if (userDetails != null) {
            return userDetails;
          }
          throw new UsernameNotFoundException("User '" + username + "' not found.");
        }
      });
  }

}

我还有一个家庭控制器,将URL“/”映射到视图home.html 当我运行应用程序并转到localhost:8080 /我得到主页。 当我尝试访问URL“/ readingList”时,我获得了自定义登录页面。如果我输入的凭据不正确,我会返回登录页面再试一次。如果我输入有效的凭证,我会得到readingList页面。到现在为止还挺好。问题出在logoutSuccessURL(“/”)上。当我转到URL“/ logout”时,这应该让我退出并将我带回“/”,但我在浏览器中显示以下错误:

Whitelabel Error Page

This application has no explicit mapping for /error, so you are seeing this as a fallback.
Thu Mar 03 19:31:24 PST 2016
There was an unexpected error (type=Not Found, status=404).
No message available

我启用了安全性调试,当我点击我的注销链接时,我得到以下内容:

2016-03-03 19:48:45.033 DEBUG 22401 --- [io-8080-exec-10] o.s.web.servlet.DispatcherServlet        : DispatcherServlet with name 'dispatcherServlet' processing GET request for [/error]
2016-03-03 19:48:45.033 DEBUG 22401 --- [io-8080-exec-10] s.w.s.m.m.a.RequestMappingHandlerMapping : Looking up handler method for path /error
2016-03-03 19:48:45.036 DEBUG 22401 --- [io-8080-exec-10] s.w.s.m.m.a.RequestMappingHandlerMapping : Returning handler method [public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)]
2016-03-03 19:48:45.036 DEBUG 22401 --- [io-8080-exec-10] o.s.web.servlet.DispatcherServlet        : Last-Modified value for [/error] is: -1
2016-03-03 19:48:45.046 DEBUG 22401 --- [io-8080-exec-10] o.s.w.s.v.ContentNegotiatingViewResolver : Requested media types are [text/html, text/html;q=0.8] based on Accept header types and producible media types [text/html])
2016-03-03 19:48:45.047 DEBUG 22401 --- [io-8080-exec-10] o.s.w.s.v.ContentNegotiatingViewResolver : Returning [org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration$SpelView@7ae1a0fb] based on requested media type 'text/html'
2016-03-03 19:48:45.047 DEBUG 22401 --- [io-8080-exec-10] o.s.web.servlet.DispatcherServlet        : Rendering view [org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration$SpelView@7ae1a0fb] in DispatcherServlet with name 'dispatcherServlet'
2016-03-03 19:48:45.055 DEBUG 22401 --- [io-8080-exec-10] o.s.web.servlet.DispatcherServlet        : Successfully completed request

我不确定为什么DispatcherServlet试图查找“/ error”。我也没有被注销,因为如果我再次尝试访问URL“/ readingList”,则不会提示我输入凭据。

我通过loggin进行了一些测试,然后手动转到URL“/ logout”。我的日志中有以下内容:

2016-03-04 16:39:31.170 DEBUG 24395 --- [nio-8080-exec-6] o.s.security.web.FilterChainProxy        : /logout reached end of additional filter chain; proceeding with original chain
2016-03-04 16:39:31.170 DEBUG 24395 --- [nio-8080-exec-6] o.s.web.servlet.DispatcherServlet        : DispatcherServlet with name 'dispatcherServlet' processing GET request for [/logout]
2016-03-04 16:39:31.170 DEBUG 24395 --- [nio-8080-exec-6] s.w.s.m.m.a.RequestMappingHandlerMapping : Looking up handler method for path /logout
2016-03-04 16:39:31.171 DEBUG 24395 --- [nio-8080-exec-6] s.w.s.m.m.a.RequestMappingHandlerMapping : Did not find handler method for [/logout]
2016-03-04 16:39:31.171 DEBUG 24395 --- [nio-8080-exec-6] o.s.w.s.handler.SimpleUrlHandlerMapping  : Matching patterns for request [/logout] are [/**]
2016-03-04 16:39:31.171 DEBUG 24395 --- [nio-8080-exec-6] o.s.w.s.handler.SimpleUrlHandlerMapping  : URI Template variables for request [/logout] are {}
2016-03-04 16:39:31.172 DEBU                G 24395 --- [nio-8080-exec-6] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapping [/logout] to HandlerExecutionChain with handler [ResourceHttpRequestHandler [locations=[ServletContext resource [/], class path resource [META-INF/resources/], class path resource [resources/], class path resource [static/], class path resource [public/]], resolvers=[org.springframework.web.servlet.resource.PathResourceResolver@e146f93]]] and 1 interceptor
2016-03-04 16:39:31.172 DEBUG 24395 --- [nio-8080-exec-6] o.s.web.servlet.DispatcherServlet        : Last-Modified value for [/logout] is: -1
2016-03-04 16:39:31.172 DEBUG 24395 --- [nio-8080-exec-6] o.s.web.servlet.DispatcherServlet        : Null ModelAndView returned to DispatcherServlet with name 'dispatcherServlet': assuming HandlerAdapter completed request handling
2016-03-04 16:39:31.173 DEBUG 24395 --- [nio-8080-exec-6] o.s.web.servlet.DispatcherServlet        : Successfully completed request
2016-03-04 16:39:31.173 DEBUG 24395 --- [nio-8080-exec-6] o.s.s.w.a.ExceptionTranslationFilter     : Chain processed normally
2016-03-04 16:39:31.173 DEBUG 24395 --- [nio-8080-exec-6] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
2016-03-04 16:39:31.196 DEBUG 24395 --- [nio-8080-exec-6] o.s.web.servlet.DispatcherServlet        : DispatcherServlet with name 'dispatcherServlet' processing GET request for [/error]
....

似乎“/ logout”网址无效,我不承诺。我虽然默认的注销网址是“/ logout”。

2 个答案:

答案 0 :(得分:3)

我在这里找到了一个类似项目的解决方案,http://spr.com/part-5-integrating-spring-security-with-spring-boot-web/。在我的安全配置中,我更改了

.logout()
  .logoutSuccessUrl("/")  
  .and()
    ...

.logout()
   .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
      .logoutSuccessUrl("/")  
      .and()
      ...

我不确定这是否是"首选"解决方案,我不知道为什么需要调用logoutRequestMatcher(...)。我有其他(非Spring-Boot)Spring Security项目不能使用logoutRequestMatcher(...)调用,而.logout(...)。logoutSuccessUrl(...)调用工作得很好

答案 1 :(得分:0)

            .and()      
            .logout()
            .invalidateHttpSession(true)
            .logoutUrl("/logout")
            .permitAll();

我更喜欢这种解决方案,因为它会擦除会话数据,因此您无法再访问,请确保在浏览器中打开开发人员工具并查看会话!!