spring jwt解码器openid令牌

spring jwt解码器openid令牌,spring,spring-security,oauth-2.0,spring-security-oauth2,Spring,Spring Security,Oauth 2.0,Spring Security Oauth2,外部OAuth2提供程序没有公共JwkUri,因此我也尝试使用以下代码段覆盖默认行为: @EnableWebSecurity public class DirectlyConfiguredJwkSetUri extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRe

外部OAuth2提供程序没有公共JwkUri,因此我也尝试使用以下代码段覆盖默认行为:

@EnableWebSecurity
public class DirectlyConfiguredJwkSetUri extends WebSecurityConfigurerAdapter {
 @Override
protected void configure(HttpSecurity http) throws Exception {
    http
            .authorizeRequests()
            .antMatchers("**/oauth2/code/esia**", "**/code/esia**", "**esia**").permitAll()
            .antMatchers("/user").fullyAuthenticated()
            .anyRequest().authenticated()
            .and()
            .csrf().disable()
            .cors().disable()
            .oauth2Client()
            .clientRegistrationRepository(this.clientRegistrationRepository)
            .authorizationCodeGrant()
            .authorizationRequestResolver(new CustomAuthorizationRequestResolver(
                    this.clientRegistrationRepository, esiaConfig, signatureUtil, timeUtil))
            .accessTokenResponseClient(customAccessTokenResponseClient())
            .and().and().oauth2Login().tokenEndpoint().accessTokenResponseClient(customAccessTokenResponseClient())
            .and().and().oauth2ResourceServer().jwt();
}
@Bean
JwtDecoder jwtDecoder() {
 return  new CustomJwtDecoder();
}
}

class CustomJwtDecoder implements JwtDecoder {
@Override
public Jwt decode(String token) throws JwtException {
    System.out.println(token);
    return null;
}
}
然而,SpringSecurity仍然使用默认实现,我得到以下错误

[missing_signature_verifier] Failed to find a Signature Verifier for Client Registration: 'esia'. Check to ensure you have configured the JwkSet URI.
另外,我尝试设置自定义AuthenticationProvider,但spring忽略了它


我想问题在于spring的OAuth2LoginConfigurater方法init(bHTTP)调用了新的OidcAuthorizationCodeAuthenticationProvider(accessTokenResponseClient,oidcUserService)

用于5.1.3版本。看起来您无法轻松解决这个问题

它源于

这种情况发生在调用私有方法时

@覆盖
公共身份验证(身份验证)引发AuthenticationException{
...
OidcIdToken idToken=createOidcToken(clientRegistration,accessTokenResponse);
...
}
我看到的一个选项是,如果您复制此代码,并自己修改它。扩展类本身没有意义,因为所有逻辑几乎都发生在
authenticate
方法中。所以你仍然在覆盖它。然后使用
http.authenticationProvider
方法添加提供者

另一个选项是重写
OAuth2LoginConfiguler
类的方法,并在那里做一些聪明的事情。就像通过反射填充图像一样

两者都不是公认的首选解决方案。我相信这就是5.2版本发生重构的原因

考虑到最新的5.2.x版本 您就快到了,但必须覆盖正确的bean

    @Bean
    public JwtDecoderFactory<ClientRegistration> jwtDecoderFactory() {
        final JwtDecoder decoder = jwtDecoder();
        return context -> decoder;

    }
@Bean
公共JwtDecoderFactory JwtDecoderFactory(){
最终JwtDecoder解码器=JwtDecoder();
返回上下文->解码器;
}
如果你不想使用lambdas

@Bean
公共JwtDecoderFactory JwtDecoderFactory(){
最终JwtDecoder解码器=JwtDecoder();
返回新的JwtDecoderFactory(){
@凌驾
公共JwtDecoder createDecoder(ClientRegistration上下文){
返回解码器;
}
};
}
我是怎么弄明白的,我看了一下这个班

JwtDecoderFactory JwtDecoderFactory=getJwtDecoderFactoryBean();
获取bean的私有方法如下所示

private JwtDecoderFactory getJwtDecoderFactoryBean(){
ResolvableType=ResolvableType.forClassWithGenerics(JwtDecoderFactory.class,ClientRegistration.class);
字符串[]名称=this.getBuilder().getSharedObject(ApplicationContext.class).getBeanNamesfortType(类型);
如果(names.length>1){
抛出新的NonuniqueBeandDefinitionException(类型、名称);
}
如果(names.length==1){
返回(JwtDecoderFactory)this.getBuilder().getSharedObject(ApplicationContext.class).getBean(名称[0]);
}
返回null;
}

即使在5.2.x版本中,我也面临同样的问题。在我的例子中,真正的问题不在JWT解码器中。我已经通过设置jwk set uri属性解决了这个问题(您可以通过正在使用的提供商更改提供商名称,例如okta、google等):

(在寻找覆盖Jwt和Oidc令牌验证的解决方案时发现了这一点。Filip帮助我找到了解决方案,所以我想我应该添加这一点,以帮助遵循相同搜索的任何人。)

对于时间旅行测试场景,我们的jvm时钟设置为未来几个月。由于对Jwt和Oidc令牌时间戳进行了验证,登录失败

这一添加适用于我们在Spring Security 5.2.1上的应用程序

@Bean
public JwtDecoderFactory<ClientRegistration> getJWTDecoder() {
    OidcIdTokenDecoderFactory factory = new OidcIdTokenDecoderFactory();
    factory.setJwtValidatorFactory(new Function<ClientRegistration, OAuth2TokenValidator<Jwt>>() {
        @Override
        public OAuth2TokenValidator<Jwt> apply(ClientRegistration clientRegistration) {
            return new CustomTimestampIgnoringOidcTokenValidator(clientRegistration);
        }
    });
}
@Bean
公共JwtDecoderFactory getJWTDecoder(){
OidcIdTokenDecoderFactory=新的OidcIdTokenDecoderFactory();
setJwtValidatorFactory(新函数(){
@凌驾
公共OAuth2TokenValidator应用(ClientRegistration ClientRegistration){
返回新的CustomTimesIgnoringOidCtokenValidator(clientRegistration);
}
});
}

这只是将默认验证器替换为只验证其他声明的自定义验证器。

我使用的是最新版本5.1.3.Release,它还没有此工厂。我已更新了答案。除了用自己的身份验证提供程序替换整个身份验证提供程序之外,没有什么好的解决方案。
@Bean
public JwtDecoderFactory<ClientRegistration> getJWTDecoder() {
    OidcIdTokenDecoderFactory factory = new OidcIdTokenDecoderFactory();
    factory.setJwtValidatorFactory(new Function<ClientRegistration, OAuth2TokenValidator<Jwt>>() {
        @Override
        public OAuth2TokenValidator<Jwt> apply(ClientRegistration clientRegistration) {
            return new CustomTimestampIgnoringOidcTokenValidator(clientRegistration);
        }
    });
}