Cod*_*Med 23 spring spring-mvc spring-security spring-boot spring-oauth2
下面给出了快速重现问题的完整代码和说明.
HttpSession
成为null
以后的自定义实现DefaultOAuth2RequestFactory
替换当前AuthorizationRequest
与保存AuthorizationRequest
. 这将导致后续请求失败来/oauth/token
,因为CsrfFilter在之前的春季安全过滤器链/oauth/token
端点无法找到一个session
Csrf token
在null
session
与比较request
的Csrf token
.
以下流程图说明了步骤14和步骤15以某种方式 - null
通知HttpSession
.(或者可能不匹配a JSESSIONID
.)在步骤14SYSO
开始时的A 表明确实存在确实包含正确的.然而,不知何故,当步骤15触发从URL 处的客户端返回到端点的呼叫时,已经变为. CustomOAuth2RequestFactory.java
HttpSession
CsrfToken
HttpSession
null
localhost:8080/login
localhost:9999/oauth/token
断点被添加到HttpSessionSecurityContextRepository
下面的调试日志中提到的每一行.(它位于在Maven Dependencies
所述的夹authserver
eclipse项目.)这些断点确认的HttpSession
是null
,当向最终请求/oauth/token
在下面的流程图制备.(左下角流程图) 的null
HttpSession
可能是由于JSESSIONID
定制后残留在浏览器成为过时的DefaultOAuth2RequestFactory
代码运行.
如何修复此问题,以便在流程图中步骤15结束后,在HttpSession
最终调用/oauth/token
端点期间保留相同的问题?
CustomOAuth2RequestFactory.java
单击此链接可在文件共享站点查看 完整代码.我们可以猜测,这null
session
是由于1.)JSESSIONID
没有在浏览器中通过代码中的更新CustomOAuth2RequestFactory
,或2.)HttpSession
实际被null
认证.
步骤15/oauth/token
之后调用的Spring Boot调试日志清楚地表明此时没有,并且可以按如下方式读取: HttpSession
2016-05-30 15:33:42.630 DEBUG 13897 --- [io-9999-exec-10] o.s.security.web.FilterChainProxy : /oauth/token at position 1 of 12 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2016-05-30 15:33:42.631 DEBUG 13897 --- [io-9999-exec-10] o.s.security.web.FilterChainProxy : /oauth/token at position 2 of 12 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2016-05-30 15:33:42.631 DEBUG 13897 --- [io-9999-exec-10] w.c.HttpSessionSecurityContextRepository : No HttpSession currently exists
2016-05-30 15:33:42.631 DEBUG 13897 --- [io-9999-exec-10] w.c.HttpSessionSecurityContextRepository : No SecurityContext was available from the HttpSession: null. A new one will be created.
2016-05-30 15:33:42.631 DEBUG 13897 --- [io-9999-exec-10] o.s.security.web.FilterChainProxy : /oauth/token at position 3 of 12 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2016-05-30 15:33:42.631 DEBUG 13897 --- [io-9999-exec-10] o.s.s.w.header.writers.HstsHeaderWriter : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@2fe29f4b
2016-05-30 15:33:42.631 DEBUG 13897 --- [io-9999-exec-10] o.s.security.web.FilterChainProxy : /oauth/token at position 4 of 12 in additional filter chain; firing Filter: 'CsrfFilter'
2016-05-30 15:33:42.644 DEBUG 13897 --- [io-9999-exec-10] o.s.security.web.csrf.CsrfFilter : Invalid CSRF token found for http://localhost:9999/uaa/oauth/token
2016-05-30 15:33:42.644 DEBUG 13897 --- [io-9999-exec-10] w.c.HttpSessionSecurityContextRepository : SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
2016-05-30 15:33:42.644 DEBUG 13897 --- [io-9999-exec-10] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
Run Code Online (Sandbox Code Playgroud)
您可以通过以下简单步骤在几分钟内在任何计算机上重新创建问题:
1.)通过单击此链接从文件共享站点下载应用程序的压缩版本.
2.)键入以下内容解压缩应用程序: tar -zxvf oauth2.tar(4).gz
3.)authserver
通过导航到oauth2/authserver
然后键入来启动应用程序mvn spring-boot:run
.
4.)resource
通过导航到oauth2/resource
然后键入来启动应用程序mvn spring-boot:run
5.)ui
通过导航到oauth2/ui
然后键入来启动应用程序mvn spring-boot:run
6.)打开Web浏览器并导航到 http : // localhost : 8080
7.)单击Login
,然后Frodo
以用户MyRing
身份和密码输入,然后单击以提交.
8)输入5309
的Pin Code
,然后点击提交. 这将触发上面显示的错误.
春引导调试日志将显示的很多SYSO
,这给变量的值,例如XSRF-TOKEN
和HttpSession
在流程图中所示的每个步骤.该SYSO
让他们更容易理解有助于段的调试日志.所有这些SYSO
都是由其他类调用的一个类完成的,因此您可以操纵SYSO
-generating类来更改控制流中的报表.SYSO
生成类的名称是TestHTTP
,它的源代码可以在同一个demo
包中找到.
1.)选择运行authserver
应用程序的终端窗口,然后键入Ctrl-C
以停止authserver
应用程序.
2.)将三个应用程序(authserver
,resource
和ui
)作为现有的maven项目导入eclipse .
3.)在authserver
应用程序的eclipse Project Explorer中,单击以展开Maven Dependencies
文件夹,然后在其中向下滚动以单击以展开Spring-Security-web...
jar,如下图中橙色圆圈所示.然后滚动查找并展开org.springframework.security.web.context
包.然后双击打开HttpSessionSecurityContextRepository
下面屏幕截图中以蓝色突出显示的类.将断点添加到此类中的每一行.您可能希望对SecurityContextPersistenceFilter
同一包中的类执行相同操作. 这些断点将使您能够查看HttpSession
当前null
在控制流结束之前的值,但需要具有可映射到a的有效值XSRF-TOKEN
以便解析此OP.
4.)在应用程序demo
包中,在内部添加断点CustomOAuth2RequestFactory.java
.然后Debug As... Spring Boot App
启动调试器.
5.)然后重复上面的步骤6到8.您可能希望在每次新尝试之前清除浏览器的缓存.您可能希望打开浏览器开发人员工具的"网络"选项卡.
你的问题解决了吗?我一直在寻找 2FA 和 spring-security-oauth2 的完整示例。很高兴您发布了完整的概念和完整的来源。
我尝试了您的软件包,只需更改 AuthserverApplication.java 中的 1 行代码即可解决您的问题
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.formLogin().loginPage("/login").permitAll()
.and()
.requestMatchers().antMatchers("/login", "/oauth/authorize", "/secure/two_factor_authentication", "/pincode")
.and()
.authorizeRequests().anyRequest().authenticated();
// @formatter:on
}
Run Code Online (Sandbox Code Playgroud)
您的原始配置通过了 Spring Security 的身份验证链,它返回了一个空的身份验证对象。
我还建议您将 CustomOAuth2RequestFactory 的 Bean 创建更改为以下内容,以覆盖链中的所有 OAuth2RequestFactory
@Bean
public OAuth2RequestFactory customOAuth2RequestFactory(){
return new CustomOAuth2RequestFactory(clientDetailsService);
}
Run Code Online (Sandbox Code Playgroud)
对于您添加的用于处理 CSRF 的代码,您可以简单地删除它们,例如:2FA 控制器:
@Controller
@RequestMapping(TwoFactorAuthenticationController.PATH)
public class TwoFactorAuthenticationController {
private static final Logger LOG = LoggerFactory.getLogger(TwoFactorAuthenticationController.class);
public static final String PATH = "/secure/two_factor_authentication";
public static final String AUTHORIZE_PATH = "/oauth/authorize";
public static final String ROLE_TWO_FACTOR_AUTHENTICATED = "ROLE_TWO_FACTOR_AUTHENTICATED";
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
@RequestMapping(method = RequestMethod.GET)
public String auth(HttpServletRequest request, HttpSession session, HttpServletResponse resp/*, ....*/) {
System.out.println("-------- inside GET /secure/two_factor_authentication --------------");
if (AuthenticationUtil.isAuthenticatedWithAuthority(ROLE_TWO_FACTOR_AUTHENTICATED)) {
LOG.info("User {} already has {} authority - no need to enter code again", ROLE_TWO_FACTOR_AUTHENTICATED);
// throw ....;
}
else if (session.getAttribute(CustomOAuth2RequestFactory.SAVED_AUTHORIZATION_REQUEST_SESSION_ATTRIBUTE_NAME) == null) {
// LOG.warn("Error while entering 2FA code - attribute {} not found in session.", CustomOAuth2RequestFactory.SAVED_AUTHORIZATION_REQUEST_SESSION_ATTRIBUTE_NAME);
// throw ....;
}
return "pinCode";
}
@RequestMapping(method = RequestMethod.POST)
public String auth(FormData formData, HttpServletRequest req, HttpServletResponse resp,
SessionStatus sessionStatus, Principal principal, Model model)
throws IOException{
if (formData.getPinVal()!=null) {
if(formData.getPinVal().equals("5309")){
AuthenticationUtil.addAuthority(ROLE_TWO_FACTOR_AUTHENTICATED);
return "redirect:"+AUTHORIZE_PATH;
};
};
return "pinCode";
}
}
Run Code Online (Sandbox Code Playgroud)
如果您想要清理后的完整源代码,请告诉我。
归档时间: |
|
查看次数: |
1849 次 |
最近记录: |