从 Spring 引导版本 1.5.7 移动到 2.0 时出现 Oauth 2.0 错误,在 1.5 上工作正常。7.RELEASE
Oauth 2.0 error when moving from Spring boot version 1.5.7 to 2.0, was working fine on 1.5.7.RELEASE
我在 Spring Boot 1.5.7 中实现了 Oauth,但是当我切换到 2 时它显示错误 "java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null"。
根据一些研究,我发现这可能是密码存储和密码编码的问题。
我尝试过的 - 我尝试在授权服务器文件中对客户端密码进行编码,但没有任何作用,错误仍然存在。
我也尝试用 {bcrypt} 作为前缀保存密码,因为 spring security 5 在密码搜索过程中寻找 ann {id}。
我无法获取访问令牌,但上面的错误并没有出现。有人可以帮我解决这个问题吗?我已经阅读并实施了几乎所有内容,但它似乎不起作用。
更新: 我能够通过以 {bcrypt} 格式保存密码来解决上述错误。同样在其他需要的地方应用 passwordEncoder。
问题: 我现在遇到凭据错误的错误。我已经调试并发现它没有获得我们试图传入 api 的用户名并接收到 null 参数。流到达 userDetailservice 但带有 epmty 参数。我已经附上了我的 UserDetailsService。
SecurityConfig.java
@Configuration
@EnableWebSecurity
public class OAuth2SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private ClientDetailsService clientDetailsService;
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private CustomPasswordEncoder customPasswordEncoder;
@Autowired
public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(customPasswordEncoder);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.anonymous().disable()
.authorizeRequests()
.antMatchers("/oauth/token").permitAll();
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
@Autowired
public TokenStoreUserApprovalHandler userApprovalHandler(TokenStore tokenStore) {
TokenStoreUserApprovalHandler handler = new TokenStoreUserApprovalHandler();
handler.setTokenStore(tokenStore);
handler.setRequestFactory(new DefaultOAuth2RequestFactory(clientDetailsService));
handler.setClientDetailsService(clientDetailsService);
return handler;
}
@Bean
@Autowired
public ApprovalStore approvalStore(TokenStore tokenStore) throws Exception {
TokenApprovalStore store = new TokenApprovalStore();
store.setTokenStore(tokenStore);
return store;
}
@Bean
public BCryptPasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
}
AuthorizationServerConfig.java
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
private static String REALM = "api-security";
@Value("${app.oauth.client-id}")
private String CLIENT_ID;
@Value("${app.oauth.client-secret}")
private String CLIENT_SECRET;
@Value("${app.oauth.access-token-validity}")
private int accessTokenValidity;
@Value("${app.oauth.refresh-token-validity}")
private int refreshTokenValidity;
@Autowired
@Qualifier("tokenStore")
private TokenStoreService tokenStore;
@Autowired
private UserApprovalHandler userApprovalHandler;
@Autowired
private BCryptPasswordEncoder passwordEncoder;
@Autowired
@Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory().withClient(CLIENT_ID)
.authorizedGrantTypes("password", "authorization_code", "refresh_token", "implicit")
.authorities("ROLE_ADMIN").scopes("read", "write", "trust").secret(passwordEncoder.encode(CLIENT_SECRET))
.accessTokenValiditySeconds(accessTokenValidity).refreshTokenValiditySeconds(refreshTokenValidity);
System.out.println(passwordEncoder.encode(CLIENT_SECRET));
System.out.println(CLIENT_SECRET);
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore).userApprovalHandler(userApprovalHandler)
.authenticationManager(authenticationManager);
}
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.realm(REALM + "/client");
}
}
UserDetailsService.java
@Configuration
@EnableWebSecurity
public class OAuth2SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private ClientDetailsService clientDetailsService;
@Autowired
@Qualifier("userDetailsService")
private UserDetailsService userDetailsService;
@Autowired
public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.anonymous().disable()
.authorizeRequests()
.antMatchers("/oauth/token").permitAll();
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
@Autowired
public TokenStoreUserApprovalHandler userApprovalHandler(TokenStore tokenStore) {
TokenStoreUserApprovalHandler handler = new TokenStoreUserApprovalHandler();
handler.setTokenStore(tokenStore);
handler.setRequestFactory(new DefaultOAuth2RequestFactory(clientDetailsService));
handler.setClientDetailsService(clientDetailsService);
return handler;
}
@Bean
@Autowired
public ApprovalStore approvalStore(TokenStore tokenStore) throws Exception {
TokenApprovalStore store = new TokenApprovalStore();
store.setTokenStore(tokenStore);
return store;
}
@Bean
public PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
// @Bean
// @Override
// public UserDetailsService userDetailsServiceBean() throws Exception {
// return super.userDetailsServiceBean();
// }
// @Bean
// public UserDetailsService userDetailsService() {
// return super.userDetailsService();
// }
}
对于觉得有用的人,我可以通过以下几点解决这个问题:
如果您清除访问令牌集合或 table,您将能够获得一次访问令牌,仅此而已。之后您执行的每个请求都会出现“500 错误 - 内部服务器错误”。
发生这种情况是因为 spring 启动在发出其他请求时无法理解来自数据库的访问令牌,对此您可以使用 "org.springframework.util.SerializationUtils" 包。您可以搜索一下,它会在发出请求时序列化和反序列化访问令牌和刷新令牌。
我在 Spring Boot 1.5.7 中实现了 Oauth,但是当我切换到 2 时它显示错误 "java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null"。
根据一些研究,我发现这可能是密码存储和密码编码的问题。
我尝试过的 - 我尝试在授权服务器文件中对客户端密码进行编码,但没有任何作用,错误仍然存在。
我也尝试用 {bcrypt} 作为前缀保存密码,因为 spring security 5 在密码搜索过程中寻找 ann {id}。
我无法获取访问令牌,但上面的错误并没有出现。有人可以帮我解决这个问题吗?我已经阅读并实施了几乎所有内容,但它似乎不起作用。
更新: 我能够通过以 {bcrypt} 格式保存密码来解决上述错误。同样在其他需要的地方应用 passwordEncoder。
问题: 我现在遇到凭据错误的错误。我已经调试并发现它没有获得我们试图传入 api 的用户名并接收到 null 参数。流到达 userDetailservice 但带有 epmty 参数。我已经附上了我的 UserDetailsService。
SecurityConfig.java
@Configuration
@EnableWebSecurity
public class OAuth2SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private ClientDetailsService clientDetailsService;
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private CustomPasswordEncoder customPasswordEncoder;
@Autowired
public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(customPasswordEncoder);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.anonymous().disable()
.authorizeRequests()
.antMatchers("/oauth/token").permitAll();
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
@Autowired
public TokenStoreUserApprovalHandler userApprovalHandler(TokenStore tokenStore) {
TokenStoreUserApprovalHandler handler = new TokenStoreUserApprovalHandler();
handler.setTokenStore(tokenStore);
handler.setRequestFactory(new DefaultOAuth2RequestFactory(clientDetailsService));
handler.setClientDetailsService(clientDetailsService);
return handler;
}
@Bean
@Autowired
public ApprovalStore approvalStore(TokenStore tokenStore) throws Exception {
TokenApprovalStore store = new TokenApprovalStore();
store.setTokenStore(tokenStore);
return store;
}
@Bean
public BCryptPasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
}
AuthorizationServerConfig.java
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
private static String REALM = "api-security";
@Value("${app.oauth.client-id}")
private String CLIENT_ID;
@Value("${app.oauth.client-secret}")
private String CLIENT_SECRET;
@Value("${app.oauth.access-token-validity}")
private int accessTokenValidity;
@Value("${app.oauth.refresh-token-validity}")
private int refreshTokenValidity;
@Autowired
@Qualifier("tokenStore")
private TokenStoreService tokenStore;
@Autowired
private UserApprovalHandler userApprovalHandler;
@Autowired
private BCryptPasswordEncoder passwordEncoder;
@Autowired
@Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory().withClient(CLIENT_ID)
.authorizedGrantTypes("password", "authorization_code", "refresh_token", "implicit")
.authorities("ROLE_ADMIN").scopes("read", "write", "trust").secret(passwordEncoder.encode(CLIENT_SECRET))
.accessTokenValiditySeconds(accessTokenValidity).refreshTokenValiditySeconds(refreshTokenValidity);
System.out.println(passwordEncoder.encode(CLIENT_SECRET));
System.out.println(CLIENT_SECRET);
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore).userApprovalHandler(userApprovalHandler)
.authenticationManager(authenticationManager);
}
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.realm(REALM + "/client");
}
}
UserDetailsService.java
@Configuration
@EnableWebSecurity
public class OAuth2SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private ClientDetailsService clientDetailsService;
@Autowired
@Qualifier("userDetailsService")
private UserDetailsService userDetailsService;
@Autowired
public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.anonymous().disable()
.authorizeRequests()
.antMatchers("/oauth/token").permitAll();
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
@Autowired
public TokenStoreUserApprovalHandler userApprovalHandler(TokenStore tokenStore) {
TokenStoreUserApprovalHandler handler = new TokenStoreUserApprovalHandler();
handler.setTokenStore(tokenStore);
handler.setRequestFactory(new DefaultOAuth2RequestFactory(clientDetailsService));
handler.setClientDetailsService(clientDetailsService);
return handler;
}
@Bean
@Autowired
public ApprovalStore approvalStore(TokenStore tokenStore) throws Exception {
TokenApprovalStore store = new TokenApprovalStore();
store.setTokenStore(tokenStore);
return store;
}
@Bean
public PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
// @Bean
// @Override
// public UserDetailsService userDetailsServiceBean() throws Exception {
// return super.userDetailsServiceBean();
// }
// @Bean
// public UserDetailsService userDetailsService() {
// return super.userDetailsService();
// }
}
对于觉得有用的人,我可以通过以下几点解决这个问题:
如果您清除访问令牌集合或 table,您将能够获得一次访问令牌,仅此而已。之后您执行的每个请求都会出现“500 错误 - 内部服务器错误”。
发生这种情况是因为 spring 启动在发出其他请求时无法理解来自数据库的访问令牌,对此您可以使用 "org.springframework.util.SerializationUtils" 包。您可以搜索一下,它会在发出请求时序列化和反序列化访问令牌和刷新令牌。