spring - 如何使 Spring Security OAuth2 真正无状态/摆脱 "state"参数?

标签 spring jwt spring-security-oauth2 jsessionid stateless

我目前正在开展一个项目,我们希望用户通过 Facebook 和其他 OAuth2 提供商登录。此外,REST api 应该是无状态的。因此,不应创建/使用任何 cookie/jsessionid。对于 api 授权,通过 Facebook 成功登录后,api 会发出 JWT。使用其余 api 的 webapp 是使用 AgularJS 和 satellizer 构建的。我将代码缩减为 minimal example available on github .

工作流程思路:

  1. 用户进入网站,选择“用 facebook 登录”
  2. Web 应用程序打开一个弹出窗口,显示 facebook 登录页面
  3. 用户登录、接受和 facebook 重定向到 web 应用
  4. webapp 从 Facebook 接收 token 并使用它来登录其余 api (GET/login/facebook?code=XXXXXXXXXXXXXXXXXX)
  5. 其余的 api 返回一个 JWT。
  6. webapp 使用 JWT 授权其余 api 以进行任何进一步的请求。

工作至今

  • webapp 可以处理步骤 1 到 4
  • 如果您使用从 OAuth2ClientContextFilter 获得的重定向,则其余 api 可以处理第 5 步和第 6 步,执行 GET 到“/login/facebook”而不使用 code 参数。 (此重定向会转到 facebook,您登录后会再次重定向到 api。)
  • 其余的 api 是无状态的,没有创建/需要 jsessionid/cookies(禁​​用 csrf 并使用 SessionCreationPolicy.STATELESS)。 除了“login/facebook”调用之外,这个调用仍在创建 jsessionid。

问题

webapp 和其余 api 的“login/facebook?code=XXX”调用的组合不起作用。我发现当您执行 GET “login/facebook”时,您将被重定向到 facebook,并在 url 上附加了一个额外的状态参数。此外,当 facebook 重定向回 api 时,也会添加此状态参数。从我在网上查到的,这似乎是一种 CSRF 保护,对吧?而且我猜这个东西也在创建 jsessionid cookie?

问题

  1. 上面介绍的工作流程是否合理?
  2. 我的用例中是否需要这种 CSRF 保护?
  3. 如何禁用此行为?我的意思是,我使用了 SessionCreationPolicy.STATELESS 但 spring 仍然使用 jsessionid 创建一个 session 。那我怎样才能创建一个真正无状态的rest api呢? (至少关于 cookie...)
  4. 这是正确的做法吗?还是我错过了什么?

示例代码

如前所述,我在 GitHub 上放了一个完整的工作最小示例。在这里,我将只发布(希望是)WebSecurityConfigurerAdapter 最重要的部分。 complete file is here.

@EnableOAuth2Client
@Configuration
public class OAuth2ClientConfigurer extends WebSecurityConfigurerAdapter {

@Autowired
private OAuth2ClientContext oAuth2ClientContext;

@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
    httpSecurity
            .csrf().disable()
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).enableSessionUrlRewriting(false).and()
            .antMatcher("/**").authorizeRequests()
            .antMatchers("/login/**").permitAll()
            .anyRequest().authenticated().and()
            .exceptionHandling().authenticationEntryPoint(new Http403ForbiddenEntryPoint()).and()
            .addFilterBefore(statelessJwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
            .addFilterBefore(createSsoFilter(facebook(), facebookSuccessHandler(), "/login/facebook"), BasicAuthenticationFilter.class);
}

private OAuth2ClientAuthenticationProcessingFilter createSsoFilter(ClientResourceDetails clientDetails, AuthenticationSuccessHandler successHandler, String path) {
    OAuth2ClientAuthenticationProcessingFilter ssoFilter = new OAuth2ClientAuthenticationProcessingFilter(path);
    ssoFilter.setAllowSessionCreation(false);
    OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(clientDetails.getClient(), oAuth2ClientContext);
    ssoFilter.setRestTemplate(restTemplate);
    ssoFilter.setTokenServices(new UserInfoTokenServices(clientDetails.getResource().getUserInfoUri(), clientDetails.getClient().getClientId()));
    ssoFilter.setAuthenticationSuccessHandler(successHandler);
    return ssoFilter;
}

@Bean // handles the redirect to facebook
public FilterRegistrationBean oAuth2ClientFilterRegistration(OAuth2ClientContextFilter filter) {
    FilterRegistrationBean registration = new FilterRegistrationBean();
    registration.setFilter(filter);
    registration.setOrder(-100);
    return registration;
}

非常感谢您的帮助!

最佳答案

这是一个可选但推荐的 OAuth 2.0 功能。它由授权服务器强制执行,并且您认为它的目的是防止 csrf 攻击。

从 OAuth 2.0 RFC 复制:

state
     RECOMMENDED.  An opaque value used by the client to maintain
     state between the request and callback.  The authorization
     server includes this value when redirecting the user-agent back
     to the client.  The parameter SHOULD be used for preventing
     cross-site request forgery as described in Section 10.12.

https://www.rfc-editor.org/rfc/rfc6749#section-4.1.1

关于spring - 如何使 Spring Security OAuth2 真正无状态/摆脱 "state"参数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34290060/

相关文章:

java - 使用 JPA 通过一列连接并返回另一列

android - 使用 OkHttp + Spring 的多部分文件上传

java - spring aop执行返回类型

.net-core - 如何从.netcore中的 token 中删除“http ://schemas. xmlsoap.org/ws/2005/05/identity/urls

java - 在没有servlet api的webflux项目中使用OAuth2与Spring Security OAuth2和reactor netty

java - Web 应用程序中的 Spring 线程

Node.js:签名验证 (PS256) 在 Node.js 中成功但在 jwt.io 调试器中失败

Spring OAuth2 + JWT在访问 token 中包含其他信息JUST

spring-security - Spring Boot with Security OAuth2 - 如何使用带有 Web 登录表单的资源服务器?

php - 如何防止 Laravel API 处理查询字符串上的参数?