我正在尝试在春季启动时使用jwt来实现oauth2,并且可以正常工作,但是当我想要获取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.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
}
}
@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,例如在数据库中查找用户。
@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
,我们需要在全局版本上进行设置,以便将此信息传递给其他构建器上下文。
阅读有关它的更多信息here