首页 > 解决方案 > Oauth2 - java.lang.IllegalStateException: UserDetailsS​​ervice 是必需的。带刷新令牌

问题描述

我正在尝试在 Spring Boot 中使用 jwt 实现 oauth2,并且身份验证有效,但是当我想获取 refresh_token 时,会发生错误,指示以下内容......

java.lang.IllegalStateException:需要 UserDetailsS​​ervice。在 org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$UserDetailsS​​erviceDelegator.loadUserByUsername(WebSecurityConfigurerAdapter.java:464) 在 org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper.loadUserDetails(UserDetailsByNameServiceWrapper.java:68) 在 org .springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider.authenticate(PreAuthenticatedAuthenticationProvider.java:103) 在 org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:175) 在 org.springframework.security.oauth2.provider .token.DefaultTokenServices.refreshAccessToken(DefaultTokenServices.java:150)

我究竟做错了什么?

这些是我的文件

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

@Value("${token.secret}")
private String secret;
@Value("${server.servlet.context-path}")
private String contextPath;
@Value("${oauth2.client.id}")
public String  CLIENT_ID;
@Value("${oauth2.client.secret}")
public String  CLIENT_SECRET;
@Value("${oauth2.scope.read}")
public String  SCOPE_READ;
@Value("${oauth2.grant.types}")
public String  GRANT_TYPES;
@Value("${oauth2.scopes}")
public String  SCOPES;
@Value("${oauth2.access.token.validity}")
public Integer  TOKEN_VALID_SECONDS;
@Value("${oauth2.refresh.token.validity}")
public Integer  REFRESH_TOKEN_VALID_SECONDS;


@Autowired
private DataSource dataSource;

@Autowired
@Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;

@Override
public void configure(final AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
    oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
}

@Override
public void configure(final ClientDetailsServiceConfigurer clients) throws Exception { 
    clients.inMemory()
            .withClient(CLIENT_ID)
            .secret(passwordEncoder().encode(CLIENT_SECRET))
            .authorizedGrantTypes("password", "refresh_token", "client_credentials","authorization_code")
            .scopes("read", "write", "trust")
            .accessTokenValiditySeconds(TOKEN_VALID_SECONDS)
            .refreshTokenValiditySeconds(REFRESH_TOKEN_VALID_SECONDS);
} 

@Bean
@Primary
public DefaultTokenServices tokenServices() {
    final DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
    defaultTokenServices.setTokenStore(tokenStore());
    defaultTokenServices.setSupportRefreshToken(true);
    return defaultTokenServices;
}

@Override
public void configure(final AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
    final TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
    tokenEnhancerChain.setTokenEnhancers(Arrays.asList(tokenEnhancer()));
    endpoints.tokenStore(tokenStore()).tokenEnhancer(tokenEnhancerChain).authenticationManager(authenticationManager);

}

@Bean
public TokenStore tokenStore() {
    return new JdbcTokenStore(dataSource);
}


@Bean
public TokenEnhancer tokenEnhancer() {
    return new CustomTokenEnhancer();
}

@Bean
public BCryptPasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
}
}

这是我的 SecurityConfig 类

@EnableGlobalMethodSecurity(securedEnabled=true)
@Configuration
@RequiredArgsConstructor
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired
private final CustomUserDetailsService customUserDetailsService;
@Autowired
public BCryptPasswordEncoder passwordEncoder;

@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
    return super.authenticationManagerBean();
}

@Override
protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(customUserDetailsService)
    .passwordEncoder(passwordEncoder);
}

@Override
public void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests()
            .antMatchers("/oauth/**").permitAll()
    .antMatchers("/oauth/token/**").permitAll()
    .antMatchers("/api/**" ).authenticated()
    .anyRequest().authenticated()
    .and().formLogin().permitAll()
    .and().csrf().disable();

}

}

public class CustomUserDetailsService implements UserDetailsService {

@Autowired
private UserService userService;
//login web service url describe on properties file
@Value("${loginServiceUri}")
public String loginServiceUri;
//login web service enabled 
@Value("${loginWebServiceEnabled}")
public Boolean loginWebServiceEnabled;


@Override
public UserDetails loadUserByUsername(String username) {

    log.debug("Trying to authenticate user with details....");

    if (loginWebServiceEnabled && loginServiceUri != null){
        //its necessary to call external Web Service to find the user and then look for 
        //into database
        UserDto userDto = this.loginWebService(username);

        if (userDto != null) {
            // look for the user in data base
            log.debug("User found at external login web service trying to look for at data base");
            return lookUserDataBase(userDto.getUsername());
        } else {
            log.error("User not found at external login web service", username);
            throw new UsernameNotFoundException(username);
        }

    } else {
        // look for the user in data base
        return lookUserDataBase(username);
    }


}

/**
 * Look for use in data base by user name

 * @return
 */
private UserDetails lookUserDataBase(String userName) {
    UserEntity user = userService.findEntityByUsername(userName);
    if (user == null) {
        log.error("User not found in data base", userName);
        throw new UsernameNotFoundException(userName);
    }
    log.debug("User found in data base with userName: " + userName + " and authorities: " + user.getUserAuthority().toString());
    return new UserAuthenticatedDetails(user);
}


/**
 *  Example Login Web Service call login 
 * @param name
 * @return
 */
private UserDto loginWebService (String name){
    xxxxxxxxxxx
}

}

标签: springspring-bootoauth-2.0spring-security-oauth2

解决方案


WebSecurityConfigurerAdapter在你的课堂上添加这些

@Autowired
public void setApplicationContext(ApplicationContext context) {
    super.setApplicationContext(context);
    AuthenticationManagerBuilder globalAuthBuilder = context
            .getBean(AuthenticationManagerBuilder.class);
    try {
        globalAuthBuilder.userDetailsService(userDetailsService);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

有一个“本地”AuthenticationManagerBuilder和一个“全局” AuthenticationManagerBuilder,我们需要在全局版本上设置它,以便将此信息传递给这些其他构建器上下文。

在此处阅读有关它的更多信息


推荐阅读