refresh_token grant_type错误:需要UserDetailsS​​ervice。但我不想指定一个

我正在尝试使用Spring Boot和依赖项创建Oauth身份验证/授权服务器  * spring-security-oauth2-autoconfigure  * nimbus-jose-jwt

我正在关注docs.spring.io/spring-security-oauth2-boot/docs/current-SNAPSHOT/reference/htmlsingle/#boot-features-security-oauth2-authorization-server

问题是我不想指定UserDetailsS​​ervice,因为有关用户帐户的信息位于另一个不公开密码的服务中。该服务只有一个API,其中输入是用户/密码,输出是用户信息(如果用户存在/凭据正确)。

所以我的代码/配置与文档略有不同。

@EnableAuthorizationServer
@Configuration
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

     //injections

   @Override
   public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
       endpoints
               .tokenStore(jwtTokenStore)
               .accessTokenConverter(accessTokenConverter)
               .authenticationmanager(authenticationmanager);
   }
}

@EnableWebSecurity
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

   //injections

    @Bean
    @Override
    public Authenticationmanager authenticationmanagerBean() throws Exception {
        return super.authenticationmanagerBean();
    }

    @Override
    protected void configure(AuthenticationmanagerBuilder authenticationmanagerBuilder) {
        authenticationmanagerBuilder.authenticationProvider(travelerauthenticationProvider); //my custom // authentication provider that calls the other service for checking credentials
    }
}

@Component
public class TravelerauthenticationProvider implements AuthenticationProvider {

    private static final Logger LOGGER = LoggerFactory.getLogger(TravelerauthenticationProvider.class);

    private OrderTravelerProfileclient travelerProfileclient;

    public TravelerauthenticationProvider(OrderTravelerProfileclient travelerProfileclient) {
        this.travelerProfileclient = travelerProfileclient;
    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        if (authentication.getName() == null || (authentication.getcredentials().toString().isEmpty())) {
            return null;
        }
        var username = authentication.getName();
        var password = authentication.getcredentials().toString();
        try {
            travelerProfileclient.authenticate(username,password);
        } catch (Exception e) {
            LOGGER.error("checking traveler {} credentials failed",username,e);
            throw new BadCredentialsException("wrong traveler credentials");
        }
        var authorities = Set.of(new SimpleGrantedAuthority("traveler"));
        var updatedAuthentication = new usernamePasswordauthenticationToken(username,password,authorities);
        return updatedAuthentication;
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return authentication.equals(usernamePasswordauthenticationToken.class);
    }
}

与client_credentials和密码流相关的所有工作均正常,但是当我尝试使用refresh_token流时,它抱怨UserDetailsService is required。在不定义UserDetailsS​​ervice且仅中继自定义身份验证提供程序的情况下,如何解决该问题?

更新: 显然,refresh_token流具有对身份验证(凭据)的重新检查,该身份验证需要使用另一个身份验证提供程序来输入PreAuthenticatedAuthenticationToken.class类型。

所以我创建了一个新的身份验证提供程序,如下所示:

@Component
public class TravelerRefreshTokenBasedAuthenticationProvider implements AuthenticationProvider {

    private static final Logger LOGGER = LoggerFactory.getLogger(TravelerRefreshTokenBasedAuthenticationProvider.class);


    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        var currentAuthentication = (PreAuthenticatedAuthenticationToken) authentication;
            //.....
        return updatedAuthentication;
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return authentication.equals(PreAuthenticatedAuthenticationToken.class);
    }
}

并将我的安全配置更新为:

@EnableWebSecurity
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

//injections

    //this bean will be more configured by the method below and it will be used by spring boot
    //for authenticating requests. Its kind of an equivalent to userDetailsService
    @Bean
    @Override
    public Authenticationmanager authenticationmanagerBean() throws Exception {
        return super.authenticationmanagerBean();
    }

    @Override
    protected void configure(AuthenticationmanagerBuilder authenticationmanagerBuilder) {
        authenticationmanagerBuilder.authenticationProvider(travelerUserPassBasedAuthenticationProvider);
        authenticationmanagerBuilder.authenticationProvider(travelerRefreshTokenBasedAuthenticationProvider);
    }
}

问题是spring无法在refresh_token流中识别我的身份验证提供程序,并尝试使用默认的身份验证提供程序。而且默认的方法是尝试使用不存在的UserDetailsS​​ervice。

我还觉得我不需要创建另一个提供程序,并且可以重用前一个提供程序。因为检查哪个spring不能使用我的自定义提供程序是针对用户/ pass的检查;我在以前的身份验证提供程序中所做的。

总而言之,直到现在,我觉得我不得不引入我的自定义提供程序来使refresh_token流与密码流相比有所不同

longayang 回答:refresh_token grant_type错误:需要UserDetailsS​​ervice。但我不想指定一个

您的AuthenticationProvider实现仅支持用于用户名/密码验证的UsernamePasswordAuthenticationToken,而refresh_token流尝试使用PreAuthenticatedAuthenticationToken更新验证(请参阅{{3 }})。

因此,您需要为AuthenticationProvider创建另一个PreAuthenticatedAuthenticationToken并将其添加到AuthenticationManagerBuilder

更新

我发现AuthorizationServerEndpointsConfigurer创建了DefaultTokenServices的新实例(如果未分配),这反过来又创建了PreAuthenticatedAuthenticationProvider的新实例,并且不使用提供的{{ 1}}。为避免这种情况,您可以创建自己的AuthenticationManager实例并将其传递给DefaultTokenServices

AuthorizationServerEndpointsConfigurer
本文链接:https://www.f2er.com/3074602.html

大家都在问