BCryptPasswordEncoder与Spring Security工作机制及登录异常疑问
解答你的BCryptPasswordEncoder与Spring Security认证疑问
为什么每次生成的BCrypt哈希值都不一样?
这是BCrypt的设计特性,完全正常!
BCryptPasswordEncoder在生成哈希时,会自动生成一个随机的盐值(salt),这个盐值会和你的原始密码一起参与哈希计算,并且最终生成的哈希字符串里会包含这个盐值(你可以仔细看生成的哈希,格式类似$2a$10$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx,其中$10$后面的部分就是盐和哈希结果的组合)。
因为每次生成的盐都是随机的,所以最终的哈希字符串看起来完全不同,但它们都对应同一个原始密码。当验证密码时,BCrypt会从存储的哈希字符串中提取出盐值,用这个盐和输入的密码重新计算哈希,再和存储的哈希对比——只要输入的密码正确,不管用哪个同密码生成的哈希,都能验证通过。
为什么重启项目后更换哈希能登录,运行时修改却不行?
这大概率是Spring Security的认证信息缓存机制在起作用:
重启项目的情况:当你停止并重启项目时,所有内存中的缓存(包括用户认证信息、UserDetails对象缓存)都会被清空。新的登录请求会直接去数据库查询最新的哈希值,然后用输入的密码验证,自然能通过。
运行时修改的情况:
- 如果是已登录的用户:他们的会话中已经保存了认证后的SecurityContext(包含用户的认证凭证),所以后续请求不需要再去数据库查询密码,仍然可以正常访问受保护页面。
- 如果是新的登录请求无法登录,建议排查这几个点:
- 数据库的修改是否真正提交(比如是否在未提交的事务中操作);
- 有没有配置用户信息的缓存,缓存是否还未过期;
- 数据库字段长度是否足够存储BCrypt哈希(BCrypt哈希通常在60字符左右,建议设为
VARCHAR(255)避免截断)。
补充说明:Spring Security的jdbcAuthentication()默认是每次登录都会查询数据库的,除非你主动配置了缓存。如果没配置缓存,运行时修改哈希后新的登录请求应该能正常验证通过,这时候可以检查下数据库的修改是否真的生效了。
内容的提问来源于stack exchange,提问作者İlkay Gunel
相关产品推荐
相关产品推荐

