Spring boot Spring cloud Zuul和JWT刷新令牌

Spring boot Spring cloud Zuul和JWT刷新令牌,spring-boot,spring-security,jwt,netflix-zuul,cloudfoundry-uaa,Spring Boot,Spring Security,Jwt,Netflix Zuul,Cloudfoundry Uaa,我有一个使用spring云组件(eureka、zuul和auth服务器)的本地协调环境。这些组件都作为单独的独立服务实现。然后,我有了越来越多的组合UI/资源服务,其中各个服务都有自己的UI。UI使用thymeleaf模板在服务器端组装,但本质上是在浏览器中运行的angularjs单页应用程序 单个Zuul服务面向所有ui/资源服务。我已经注释了所有ui/resource服务@EnableResourceServer,并将@EnableOAuth2Sso添加到Zuul服务器 在Zuul的appl

我有一个使用spring云组件(eureka、zuul和auth服务器)的本地协调环境。这些组件都作为单独的独立服务实现。然后,我有了越来越多的组合UI/资源服务,其中各个服务都有自己的UI。UI使用thymeleaf模板在服务器端组装,但本质上是在浏览器中运行的angularjs单页应用程序

单个Zuul服务面向所有ui/资源服务。我已经注释了所有ui/resource服务
@EnableResourceServer
,并将
@EnableOAuth2Sso
添加到Zuul服务器

在Zuul的application.properties中,我具有以下属性:

security.oauth2.client.accessTokenUri=http://localhost:8771/uaa/oauth/token
security.oauth2.client.userAuthorizationUri=http://localhost:8771/uaa/oauth/authorize
security.oauth2.client.clientId=waharoa
security.oauth2.client.clientSecret=waharoa
security.oauth2.client.preEstablishedRedirectUri=http://localhost:81/login
security.oauth2.client.registeredRedirectUri=http://localhost:81/login
security.oauth2.client.useCurrentUri=false
security.oauth2.resource.jwt.keyValue=-----BEGIN PUBLIC KEY-----[ETC omitted]...
这一切似乎都像广告宣传的那样奏效。我的问题是令牌何时过期

在Auth服务器中,我将令牌设置为60秒后过期,刷新令牌设置为12小时后过期。当令牌过期时,zuul服务器无法获取新令牌

在zuul服务器上,这会出现在日志中:

BadCredentialsException:无法获取OAuth2TokenReayFilter.getAccessToken引发的有效访问令牌

更新: 我在Zuul服务中打开了org.springframework.security.oauth的调试,得到了以下结果

    17:12:33.279 DEBUG o.s.s.o.c.t.g.c.AuthorizationCodeAccessTokenProvider - Retrieving token from http://localhost:8771/uaa/oauth/token
    17:12:33.289 DEBUG o.s.s.o.c.t.g.c.AuthorizationCodeAccessTokenProvider - Encoding and sending form: {grant_type=[refresh_token], refresh_token=[eyJhbGciOiJS[...deleted...]VgGRHGT8OJ2yDfNVvNA]}
    17:12:37.279 WARN  o.s.c.n.z.f.post.SendErrorFilter - Error during filtering
[blah blah stacktrace many lines omitted]
Caused by: org.springframework.security.authentication.BadCredentialsException: Cannot obtain valid access token
        at org.springframework.cloud.security.oauth2.proxy.OAuth2TokenRelayFilter.getAccessToken(OAuth2TokenRelayFilter.java:99)
        at org.springframework.cloud.security.oauth2.proxy.OAuth2TokenRelayFilter.run(OAuth2TokenRelayFilter.java:79)
        at com.netflix.zuul.ZuulFilter.runFilter(ZuulFilter.java:112)
        at com.netflix.zuul.FilterProcessor.processZuulFilter(FilterProcessor.java:193)
        ... 106 common frames omitted
在身份验证(uaa)服务端,我可以看到zuul客户端(waharoa)进行身份验证,获取正确用户的详细信息,然后打印:

17:12:37.288 DEBUG o.s.s.w.c.SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as request processing completed
我猜想这意味着身份验证服务器已经完成了它需要做的事情,并响应了请求?Zuul服务似乎设置不正确,有什么建议吗

请有人告诉我需要在这里发布哪些其他信息来了解令牌刷新不起作用的原因。我是一个springcloudnoob,这个惯例的黑魔法对我来说不是很清楚(我已经搜索了一个又一个我认为是常见用例的例子,但什么也没有找到)

注2:我已经在Zuul端有以下bean

@Bean
    public OAuth2RestTemplate oauth2RestTemplate(OAuth2ProtectedResourceDetails resource, OAuth2ClientContext context) {
        return new OAuth2RestTemplate(resource, context);
    }
在@AlexK建议之后,我还在Auth端添加了以下UserDetailsService Bean

@Bean
    @Override
    public UserDetailsService userDetailsServiceBean() throws Exception {
        return super.userDetailsServiceBean();
    }
并将其添加到我的身份验证服务器配置中

@Autowired
    private UserDetailsService userDetailsService;

@Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.tokenStore(tokenStore()).tokenEnhancer(jwtTokenEnhancer())
                .authenticationManager(authenticationManager).userDetailsService(userDetailsService)
            .reuseRefreshTokens(false);
}
但结果是一样的。刷新令牌发生了,但当响应到达Zuul筛选器时,它似乎仍然会消失

注3:

@事实上,亚历克斯是正确的。我发现,当令牌被刷新时,它不仅仅是从令牌存储中刷新,它还需要调用底层的userdetails服务来再次获取用户详细信息。当我从Active Directory获得详细信息时,这需要大量的尝试和错误来解决,但现在已如广告所示工作。我(缺少)的简单UserDetails服务bean,它自动连接到配置中,如注释2所示:

@Bean(name = "ldapUserDetailsService")
public UserDetailsService userDetailsService() {
    FilterBasedLdapUserSearch userSearch = new FilterBasedLdapUserSearch(searchBase, "(sAMAccountName={0})",
            contextSource());
    LdapUserDetailsService result = new LdapUserDetailsService(userSearch);
    result.setUserDetailsMapper(new InetOrgPersonContextMapper());
    return result;
}

我认为所有必要的线索都在问答中

简言之:

  • 有问题的线索-有必要在Zuul/UIApp端实现OAuth2RestTemplate。正如中所说,它不是默认创建的
  • 另一部分在答案中-有必要在OAuth服务器端进行某些修改
  • 之后,您将通过刷新令牌自动刷新您的访问令牌

    附言。 但当您刷新\u token token并使其过期时,仍然会出现相同的外观错误!为了解决这个问题,您可以在获得新的访问令牌的同时自动更新您的刷新令牌。在auth server代码处的AuthorizationServerEndpointsConfiger配置中使用reuseRefreshTokens(false):

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints)
            throws Exception {
        endpoints
            .authenticationManager(authenticationManager)
            .userDetailsService(userDetailsService)
            .reuseRefreshTokens(false); // <--that's the key to get new refresh_token at the same time as new access_token
    }
    
    @覆盖
    公共无效配置(授权服务器端点配置器端点)
    抛出异常{
    端点
    .authenticationManager(authenticationManager)
    .userDetailsService(userDetailsService)
    
    .reuseRefreshTokens(false);//谢谢你的回复。我已经在Zuul端有了OAuth2RestTemplate。我确实注意到来自身份验证的信息说没有UserDetails服务,所以我根据你的链接添加了它。不幸的是,我仍然得到相同的结果。刷新)令牌过程似乎工作正常,但Zuul筛选器仍然引发异常。我仍然不知道这是为什么。你说得对。我的UserDetails服务出现了问题。恭喜!也许未来的读者可以知道你的UserDetails服务有什么问题。我很感兴趣。我在问题中添加了一条更新说明,其中包括我必须添加的代码,以便与Active Directory连接。再次感谢。