Spring Security和Azure-重新启动后,应用尝试重新授权,但是Azure重定向到redirect-uri的结果为404

时间:2019-07-09 00:29:07

标签: spring-boot spring-security azure-active-directory

我正在编写一个Spring Boot 2 Webapp。它使用Azure AD进行用户身份验证(使用授权代码流和委派权限),并利用了Spring Security的OAuth 2.0登录支持。它还尝试访问Microsoft Graph资源。但是,它没有在春季使用Microsoft的Azure库。

在大多数情况下,以下代码可以正常工作。 (我在本地运行。)

@Autowired
private RestTemplateBuilder restTemplateBuilder;

@RequestMapping("/aboutMe")
public String aboutMe(Model model,
                      @RegisteredOAuth2AuthorizedClient("azure") OAuth2AuthorizedClient authorizedClient) {
    String accessTokenValue = authorizedClient.getAccessToken().getTokenValue();

    RestTemplate restTemplate = buildRestTemplate(accessTokenValue);

    String user = restTemplate.getForObject("https://graph.microsoft.com/v1.0/me", String.class);

    model.addAttribute("user", user);

    return "pages/me";
}

private RestTemplate buildRestTemplate(String accessTokenValue) {
    RestTemplate restTemplate = restTemplateBuilder.additionalInterceptors(
        new ClientHttpRequestInterceptor() {
            @Override
            public ClientHttpResponse intercept(HttpRequest request, byte[] bytes,
                                ClientHttpRequestExecution execution) throws IOException {

                request.getHeaders().add("Authorization", "Bearer " + accessTokenValue);

                return execution.execute(request, bytes);
            }
        }).build();

    return restTemplate;
}

但是,只有在重新启动应用程序之后,以下测试用例才能按预期工作。

测试用例

  1. 首次打开浏览器,然后导航至http://localhost:8080/aboutMe
  2. 浏览器将转到Microsoft登录页面。使用Azure AD凭据登录。
  3. 然后,浏览器将转到/aboutMe页。
  4. 关闭应用程序,然后重新启动。
  5. 不关闭浏览器。保持打开状态。
  6. 尝试再次导航至http://localhost:8080/aboutMe

实际结果

  1. 浏览器被重定向到Microsoft https://login.microsoftonline.com/[tenantId]/oauth2/v2.0/authorize端点。
  2. 然后,Microsoft authorize请求将浏览器重定向到应用程序的redirect-uri,在这种情况下,它以http://localhost:8080/login/oauth2/code/azure开头。
  3. 该应用程序响应为404-未找到。

预期结果

要么:

  • Azure AD应该再次显示登录页面,并要求用户再次进行身份验证,然后让应用正确处理;
  • 应用程序或Spring或两者都应处理重定向请求,而不是返回404。

调查

404似乎是由于该应用的redirect-uri并不总是“在听”,特别是在这种情况下。

在上面的控制器代码中,@RegisteredOAuth2AuthorizedClient("azure")导致Spring Security的OAuth2AuthorizedClientArgumentResolver抛出ClientAuthorizationRequiredException,因为它找不到OAuth2AuthorizedClient,这就是我们要解决的问题。 d期望,因为该应用已重新启动。

然后,ClientAuthorizationRequiredException使OAuth2AuthorizationRequestRedirectFilter将浏览器重定向到Azure以请求授权。

但是,Azure不会要求用户提供凭据,而是使用新的授权将浏览器重定向到应用程序的redirect-uri。 (我假设这是因为浏览器发送了带有其请求的cookie,Azure认为该请求仍然有效。)

最后,我的问题

处理这种情况的最佳方法是什么,以避免使用户感到困惑?当然,我总是可以告诉用户只关闭所有浏览器窗口,然后重试。但是,从用户的角度来看,这种行为本身并不是完全干净的。

我相信/login/oauth2/code/azure端点通常由Spring Security过滤器处理,所以我不确定如何拦截它。

也许解决方案是让应用在启动时清除浏览器中的所有cookie?但是Azure的cookie呢?

1 个答案:

答案 0 :(得分:0)

我可以通过向Spring Security配置添加.oauth2Client()来解决此问题。这是工作配置:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .authorizeRequests()
            .antMatchers("/web/**")
                .hasRole("USER")
            .antMatchers("/")
                .permitAll()
        .and()
        .oauth2Login()
            .userInfoEndpoint()
                .oidcUserService(this.oidcUserService())
            .and()
            .defaultSuccessUrl("/", false)
        .and()
        .logout()
            .logoutSuccessUrl(azureLogoutUri)
            .permitAll()
        // Without the oauth2Client(), the 404 happens
        .and()
        .oauth2Client();
}

添加.oauth2Client()会使Spring将第二个OAuth2AuthorizationRequestRedirectFilter和一个OAuth2AuthorizationCodeGrantFilter添加到安全过滤器链中。

我错误地认为不需要oauth2Client()。只有在找不到WebSecurityConfigurerAdapter的情况下,这才是正确的。