Oauth2 - java .lang.IllegalStateException: требуется UserDetailsService. с refre sh токеном - PullRequest
1 голос
/ 25 февраля 2020

Я пытаюсь реализовать oauth2 с jwt при весенней загрузке, и аутентификация работает, но когда я хочу получить refresh_token, возникает ошибка, которая указывает на следующее ...

java. lang.IllegalStateException: UserDetailsService требуется. в org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter $ UserDetailsServiceDelegator.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. .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
}

}

Ответы [ 3 ]

1 голос
/ 25 февраля 2020

Добавьте их в свой 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();
    }
}

. Существует "local" AuthenticationManagerBuilder и "global" AuthenticationManagerBuilder, и нам нужно установить его в глобальной версии, чтобы передать эту информацию в другие контексты строителя.

Подробнее об этом здесь

0 голосов
/ 25 февраля 2020

Я решил с помощью этих строк в SecurityConfig;

 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);

    //this line solved the problem
    endpoints.userDetailsService(customUserDetailsService);**


}
0 голосов
/ 25 февраля 2020

Либо вы настраиваете некоторого пользователя inMemory следующим образом:

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.inMemoryAuthentication()
            .withUser("user")
                .password("password")
                .roles("USER")
        .and()
            .withUser("manager")
                .password("password")
                .credentialsExpired(true)
                .accountExpired(true)
                .accountLocked(true)
                .authorities("WRITE_PRIVILEGES", "READ_PRIVILEGES")
                .roles("MANAGER");
}

, либо реализуете UserDetailService, например, который ищет в базе данных пользователя.

...