Spring Security - api网关模式 - bug?

时间:2016-10-14 19:57:59

标签: java spring api spring-security spring-boot

我们创建了一个模仿Spring Security - API Gate Pattern教程(https://spring.io/guides/tutorials/spring-security-and-angular-js/#_the_api_gateway_pattern_angular_js_and_spring_security_part_iv)的应用程序。唯一的变化是我们使用MySQL数据库而不是Redis。

使用localhost:8080作为root,我们有localhost:8080 / login(登录页面),localhost:8080 / ui(jQuery客户端)和localhost:8080 / api(restful web services,业务逻辑等)

我们正在寻找会话处理并转发到各个实体按预期工作。意味着会话按预期创建,转发正在按预期发生,等等。有一个例外。如果我登录,然后注销,然后直接转到localhost:8080 / ui它会转发我到登录页面。您登录后,它会将您转发回localhost:8080 / ui,但会显示" ACCESS DENIED"!

在跟踪数据库和客户端中的会话后,我发现数据库中存在两个会话。一个有权限,一个没有。客户保留没有!

还有其他人遇到过这个问题吗?有没有办法规避这个?

这是我经历的列表步骤,数据库会话跟踪和客户端验证。

    session_id                               principal_name  Client
    ------------------------------------------------------------
1)  go to localhost:8080                    
    9229045c-27e0-410a-8711-45c56576d647    -                X

2)  login                   
    2275db1c-fca4-4a2f-be73-e440599499d6    root             X

3)  logout                  
    cc917e68-b1c0-46a4-bbe3-6705ccf7a5fa    -                X

4)  go to localhost:8080/ui --> forwards to localhost:8080/login
    cc917e68-b1c0-46a4-bbe3-6705ccf7a5fa    -                X

5)  login -> forwards to  localhost:8080/ui -> Access Denied                    
    90d7931d-b265-42e2-a225-286bcf7d159c    -                X
d2fae0ac-9cf9-4287-8e38-51f64b0ab28d root

2 个答案:

答案 0 :(得分:1)

好吧,经过几个小时,我们找到了解决行为似乎不一致的问题。意思有时你会登录并且它会保留正确的会话,你可以去localhost:8080 / ui页面而不是得到Whitelabel错误页面......有时候你仍然可以得到它。

在网关服务器上...
1)添加了RequestMethod.POST

@Controller
public class HomeController {
    @RequestMapping(method = { RequestMethod.GET, RequestMethod.POST }, path = "/")
    public String home() {
        return "redirect:" + RequestMappings.UI;
    }
}

2)更改了配置文件,特别是
  a)添加.successForwardUrl(“/”)
  b)添加.loginProcessingUrl(“/ login”)
  c)添加.logoutSuccessUrl(“/ login?logout”)

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.headers()
        .frameOptions().sameOrigin()
    .and().formLogin()
        .loginPage(RequestMappings.LOGIN)
        .failureHandler(failureHandler())
        .successForwardUrl("/")
        .permitAll()
        .loginProcessingUrl("/login")
    .and().logout()
        .logoutSuccessUrl("/login?logout")
    .and().authorizeRequests()
        .antMatchers("/login").permitAll()
        .antMatchers(RequestMappings.CHANGE_PASSWORD).permitAll()
        .anyRequest().authenticated()
    .and().csrf()
        .csrfTokenRepository(csrfTokenRepository())
    .and().addFilterAfter(csrfHeaderFilter(), SessionManagementFilter.class);
}

现在,还有一种方法可以获得白页错误。如果,在登录之前,你直接去localhost:8080 / ui ....它会转发到localhost:8080 /登录页面。你登录。你将在localhost:8080 / ui /按预期查看所有内容。如果删除最后一个正斜杠,则会出现白页错误。然后从那里可以搞砸缓存中的东西。但是如果你回到根目录,你可以正常登录,一切都会正常工作。

我认为发生的事情是登录前的localhost:8080 / ui调用正在被缓存,因为一旦你重新登录并返回后你就没有加载index.html页面,你通过了授权检查,但它试图加载......好吧,没有,然后抛出一个错误。至少这是我最好的猜测。

无论如何,干杯!感谢您的帮助,让我们走上正轨!

答案 1 :(得分:0)

最有可能的是,当您直接返回UI应用程序时,它仍然使用旧的会话ID,当您登录时,它会使用旧的会话ID将您重定向到UI。

它也可能是Tomcat上的旧问题,请查看此主题以了解如何正确清除Cookie:https://straypixels.net/clearing-cookies-in-spring-tomcat/

基本上,像这样扩展SimpleUrlLogoutSuccessHandler

public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
throws IOException, ServletException {
    //This search may or may not actually be necessary, you might be able to just
    // create a new cookie with the right name
    for(Cookie cookie : request.getCookies()) {
        if(cookie.getName() == "JSESSIONID") {
            //Clear one cookie
            cookie.setName("");
            cookie.setMaxAge(0);
            cookie.setPath(request.getContextPath());
            response.addCookie(cookie);
            //Clear the other cookie
            Cookie cookieWithSlash = cookie.clone();
            cookieWithSlash.setPath(request.getContextPath() + "/");
            response.addCookie(cookieWithSlash);
        }
    }
    //This is actually a filter; continue along the chain
    super.onLogoutSuccess(request, response, authentication);
}