BCrypt:使用 Spring Security 的空编码密码
Posted
技术标签:
【中文标题】BCrypt:使用 Spring Security 的空编码密码【英文标题】:BCrypt: Empty Encoded Password with Spring Security 【发布时间】:2019-10-26 18:46:49 【问题描述】:帮助解决问题的代码示例:https://github.com/Suwappertjes/SpringSample
问题
当尝试在 Spring Boot 应用程序中实现 jwt-security 时,我遇到了以下问题:
当我尝试通过 Postman 使用 x-www-form-urlencoded 登录时,我收到 "Bad client credentials" 错误,但我知道凭据是正确的.
当我查看我的日志时,我看到 BCrypt 发出了 “空编码密码”警告。这很奇怪,考虑到当我通过 mysql 解释器查看数据库时,我在数据库中看到了正确加密的密码。
信息
我正在使用 Hibernate 构建 MySQL 数据库。
编译'org.springframework.security.oauth:spring-security-oauth2:2.3.6.RELEASE'
编译'org.springframework.security:spring-security-jwt:1.0.10.RELEASE'
编译'org.springframework.boot:spring-boot-starter-data-jpa'
Java 1.8.0_212
我尝试了什么
在开始实施安全之前,控制器、存储库和 MySQL 数据库都运行正常。
当我在网上搜索这个问题时,有人认为它与“loadUserByUsername”功能有关。但是当我调试该函数时,我注意到它根本没有被调用。
我还尝试允许程序中的每条路径并禁用 crsf
以防它与访问权限有关,但两者都没有改变任何东西。 (http.requestMatchers.andMatcher("/**").permitAll().and().csrf().disable();)
更新:将 NO users 放入数据库时,我仍然收到相同的错误。
一些代码:
loadUserByUsername 方法:
@Override
public UserDetails loadUserByUsername(String userName)
return userRepository.findByUsername(userName)
.map(user -> new User(
user.getUsername(),
user.getPassword(),
UserRoleAuthority.getAuthorities(user.getRoles())
))
.orElseThrow(() -> new UsernameNotFoundException("Unknown user: " + userName));
身份验证提供者和密码编码器:
@Bean
public DaoAuthenticationProvider getAuthenticationProvider()
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(userDetailsService);
authenticationProvider.setPasswordEncoder(passwordEncoder());
return authenticationProvider;
@Bean
PasswordEncoder passwordEncoder()
return new BCryptPasswordEncoder();
签名密钥:
@Bean
public JwtAccessTokenConverter jwtTokenEnhancer()
JwtAccessTokenConverter result = new JwtAccessTokenConverter();
result.setSigningKey(signingKey);
return result;
添加新用户:
userRepository.save(new User()
.withUsername("test")
.withPassword(passwordEncoder.encode("password"))
.withFirst("Admin")
.withLast("Nator")
.withEmail("test@notadmin.com")
.withRole(new HashSet<>(Arrays.asList(Role.Admin, Role.NotAdmin)))
);
以及Http配置:
@Override
public void configure(HttpSecurity http) throws Exception
http.requestMatchers()
.antMatchers("/iungo/*/**")
.and()
.authorizeRequests()
.antMatchers("/iungo/system/**")
.permitAll()
.antMatchers("/iungo/**");
@Override
public void configure(HttpSecurity http) throws Exception
// We don't use this endpoint but we have to define it anyway in order to not enable web security on the whole application.
http
.userDetailsService(userDetailsService)
.requestMatchers()
.antMatchers("/oauth/authorize");
最后,我的控制台:
2019-06-12 10:29:58.460 INFO 25207 --- [ main] org.hibernate.Version : HHH000412: Hibernate Core 5.3.9.Final
2019-06-12 10:29:58.461 INFO 25207 --- [ main] org.hibernate.cfg.Environment : HHH000206: hibernate.properties not found
2019-06-12 10:29:58.532 INFO 25207 --- [ main] o.hibernate.annotations.common.Version : HCANN000001: Hibernate Commons Annotations 5.0.4.Final
2019-06-12 10:29:58.599 INFO 25207 --- [ main] org.hibernate.dialect.Dialect : HHH000400: Using dialect: org.hibernate.dialect.MySQL5Dialect
2019-06-12 10:29:59.092 INFO 25207 --- [ main] o.h.t.schema.internal.SchemaCreatorImpl : HHH000476: Executing import script 'org.hibernate.tool.schema.internal.exec.ScriptSourceInputNonExistentImpl@c30f26d'
2019-06-12 10:29:59.098 INFO 25207 --- [ main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2019-06-12 10:29:59.382 WARN 25207 --- [ main] o.s.s.o.p.t.s.JwtAccessTokenConverter : Unable to create an RSA verifier from verifierKey (ignoreable if using MAC)
2019-06-12 10:29:59.595 INFO 25207 --- [ main] o.s.s.web.DefaultSecurityFilterChain : Creating filter chain: OrRequestMatcher [requestMatchers=[Ant [pattern='/oauth/token'], Ant [pattern='/oauth/token_key'], Ant [pattern='/oauth/check_token']]], [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@56a72887, org.springframework.security.web.context.SecurityContextPersistenceFilter@1ddba7a0, org.springframework.security.web.header.HeaderWriterFilter@7adbec34, org.springframework.security.web.authentication.logout.LogoutFilter@296bfddb, org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter@22ab1b8a, org.springframework.security.web.authentication.www.BasicAuthenticationFilter@54033a65, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@7dfec0bc, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@42734b71, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@3c8dea0b, org.springframework.security.web.session.SessionManagementFilter@6fe9c048, org.springframework.security.web.access.ExceptionTranslationFilter@526fc044, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@690e4b00]
2019-06-12 10:29:59.600 INFO 25207 --- [ main] o.s.s.web.DefaultSecurityFilterChain : Creating filter chain: OrRequestMatcher [requestMatchers=[Ant [pattern='/iungo/*/**']]], [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@1978b0d5, org.springframework.security.web.context.SecurityContextPersistenceFilter@69a3bf40, org.springframework.security.web.header.HeaderWriterFilter@3186f8f5, org.springframework.security.web.authentication.logout.LogoutFilter@a4dcede, org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationProcessingFilter@760c777d, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@2c731a16, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@2a341e3d, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@6556471b, org.springframework.security.web.session.SessionManagementFilter@467cd4b9, org.springframework.security.web.access.ExceptionTranslationFilter@3f3f554f, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@d0e4972]
2019-06-12 10:29:59.603 INFO 25207 --- [ main] o.s.s.web.DefaultSecurityFilterChain : Creating filter chain: OrRequestMatcher [requestMatchers=[Ant [pattern='/oauth/authorize']]], [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@6cf3b3d7, org.springframework.security.web.context.SecurityContextPersistenceFilter@462f8fe9, org.springframework.security.web.header.HeaderWriterFilter@24f2608b, org.springframework.security.web.csrf.CsrfFilter@713497cd, org.springframework.security.web.authentication.logout.LogoutFilter@56193e3a, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@3c6fc4cd, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@b2e1df3, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@2e785b28, org.springframework.security.web.session.SessionManagementFilter@12a9e864, org.springframework.security.web.access.ExceptionTranslationFilter@4b762988]
2019-06-12 10:29:59.731 INFO 25207 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2019-06-12 10:29:59.902 INFO 25207 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2019-06-12 10:29:59.903 INFO 25207 --- [ main] nl.highway.iungomain.Application : Started Application in 2.937 seconds (JVM running for 3.345)
2019-06-12 10:29:59.923 INFO 25207 --- [ main] o.h.h.i.QueryTranslatorFactoryInitiator : HHH000397: Using ASTQueryTranslatorFactory
2019-06-12 10:30:12.550 INFO 25207 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2019-06-12 10:30:12.550 INFO 25207 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2019-06-12 10:30:12.554 INFO 25207 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 4 ms
2019-06-12 10:30:12.632 WARN 25207 --- [nio-8080-exec-1] o.s.s.c.bcrypt.BCryptPasswordEncoder : Empty encoded password
【问题讨论】:
【参考方案1】:我面临着完全相同的问题。在我的情况下,原因是我的 CustomUserDetails 类构造函数,它没有为类设置密码,所以它总是为空。
此回答者的功劳: why spring security gives empty password to password encoder?
【讨论】:
【参考方案2】:我认为@ghazouanbadr 的解决方案是正确的。虽然,我在实践项目中的实现方式有所不同:
@EnableWebSecurity
@Configuration
public class WebSecurity extends WebSecurityConfigurerAdapter
@Autowired
UserService userService;
@Autowired
BCryptPasswordEncoder bCryptPasswordEncoder;
public WebSecurity(UserService userService, BCryptPasswordEncoder bCryptPasswordEncoder)
this.userService = userService;
this.bCryptPasswordEncoder = bCryptPasswordEncoder;
@Override // Authorization
protected void configure(HttpSecurity http) throws Exception
...
@Override // Authentication
public void configure(AuthenticationManagerBuilder auth) throws Exception
auth.userService(userService).passwordEncoder(bCryptPasswordEncoder);
请注意,当我创建这个课程时,我才刚开始学习 Java 一个月。不要对安全性有太多了解,所以我不能告诉你这是最好的方法。因为我记得处理过同样的问题,所以我认为它可能会引导您朝着正确的方向前进。
【讨论】:
【参考方案3】:我发现了问题。我使用的是 Spring boot 2.1.4.RELEASE,但此设置仅适用于 1.5.12.RELEASE。当然降级不是很好的做法,所以我仍然会尝试让它与 2.1.4 一起使用。
【讨论】:
【参考方案4】:你必须在 configureGlobal 方法中添加 bCryptPasswordEncoder
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception
auth
.userDetailsService(userDetailsService)
.passwordEncoder(bCryptPasswordEncoder());
【讨论】:
以上是关于BCrypt:使用 Spring Security 的空编码密码的主要内容,如果未能解决你的问题,请参考以下文章
在 Grails 3.0 中配置 Spring Boot Security 以使用 BCrypt 密码编码
使用 OAuth2 和 JWT 的 Spring Security:编码密码看起来不像 BCrypt
Spring Security bcrypt 编码登录不起作用
使用Spring Security为实时Grails应用程序增加BCrypt logrounds而不重新编码所有密码是否安全?
Spring Security:无法将我的 UserDetailService 自动连接到 AuthenticationProvider 以进行 BCrypt 集成