我正在使用 kotlin 和 Spring Boot 2.5.5 以及 MySQL 資料庫開發登錄服務。一切似乎都正常作業(注冊用戶、洗掉用戶、更新用戶),除了當我嘗試從郵遞員呼叫登錄端點時,出現錯誤:
2021-10-26 18:16:28.558 WARN 26076 --- [nio-8080-exec-2] o.s.s.c.bcrypt.BCryptPasswordEncoder : Encoded password does not look like BCrypt
我在 stackoverflow 上到處搜索,我看到其他人有這個問題,但沒有一個建議的答案對我有用(甚至在某些情況下適用于我的情況)
我的 SecurityConfig 類:
@Configuration
@EnableWebSecurity
class SecurityConfig(private val dataSource: DataSource) : WebSecurityConfigurerAdapter() {
override fun configure(auth: AuthenticationManagerBuilder) {
auth.inMemoryAuthentication()
.withUser("user").password("password")
.authorities("USER", "ADMIN", "CONTRIBUTOR")
}
override fun configure(http: HttpSecurity?) {
http!!.csrf().disable()
.authorizeRequests()
.antMatchers("/admin/**").hasAuthority("ADMIN")
.antMatchers("/contributor/**").hasAuthority("CONTRIBUTOR")
.antMatchers("/anonymous*").anonymous()
.antMatchers("/login/**").permitAll()
.antMatchers("/login*").permitAll()
.antMatchers("/**").hasAuthority("USER")
.anyRequest().authenticated()
.and()
.formLogin().permitAll()
.and()
.logout().permitAll()
}
@Autowired
fun configureGlobal(auth: AuthenticationManagerBuilder) {
auth.jdbcAuthentication()
.passwordEncoder(passwordEncoder())
.dataSource(dataSource)
.usersByUsernameQuery("select username,encrypted_password,\'true\' from dragonline.user where username=?")
.authoritiesByUsernameQuery("select user_username,roles_name from dragonline.user_has_roles where user_username=?")
}
}
class AppInitializer : WebApplicationInitializer {
override fun onStartup(servletContext: ServletContext) {
val root = AnnotationConfigWebApplicationContext()
root.register(SecurityConfig::class.java)
servletContext.addListener(ContextLoaderListener(root))
servletContext.addFilter("securityFilter", DelegatingFilterProxy("springSecurityFilterChain"))
.addMappingForUrlPatterns(null, false, "/*")
}
}
我的登錄控制器:
@RestController
@RequestMapping(path = ["/login"])
class Login(private val userRegistrationService: UserRegistrationService) {
@PostMapping(path = ["/register"], consumes = [MediaType.APPLICATION_JSON_VALUE])
fun register(@RequestBody user: UserRegistrationDTO, response: HttpServletResponse): UserRegistrationDTO {
user.confirmPassword()
val domainUser = user.toDomain()
userRegistrationService.saveUser(domainUser)
response.status = HttpServletResponse.SC_CREATED
return user.maskPassword()
}
@CrossOrigin
@PostMapping(path = ["/find-user"], consumes = [MediaType.APPLICATION_JSON_VALUE])
fun login(@RequestBody user: UserLoginDTO, response: HttpServletResponse): UserLoginDTO {
val userFound = userRegistrationService.findUser(user.username)
println("The password stored ind DB is ${userFound?.encryptedPassword}")
if (passwordEncoder().matches(userFound?.encryptedPassword, user.password)) {
response.status = HttpServletResponse.SC_OK
response.setHeader(
"Session-ID",
"${passwordEncoder().encode(user.username)}@.@${passwordEncoder().encode(user.password)}"
)
} else {
response.status = HttpServletResponse.SC_NOT_FOUND
}
return user.maskPassword()
}
@GetMapping(path = ["/delete-user/{userId}"])
fun deleteUser(@PathVariable userId: String) {
userRegistrationService.deleteUser(userId)
}
}
我的資料庫中的條目如下所示:
'test', '$2a$10$Z/FSxELmMtV2zpgFVYzDi.dprUybnzJxF6f/kZan7DqHfQ9VDjmQq', '[email protected]', 'Tester', 'Testing a Test', NULL, '0'
列分別是 username、encrypted_pa??ssword、email、name、lastnames、session_id、session_active
我的用戶服務:
@Service
@Transactional
class UserRegistrationService(
private val userRegistrationRepository: UserRegistrationRepository
) {
fun findUser(userId: String) =
userRegistrationRepository.findByUsername(userId) ?: userRegistrationRepository.findByEmail(userId)
fun saveUser(user: UserRegistrationData) =
userRegistrationRepository.save(user.toPersistence())
fun deleteUser(userId: String) {
val user = userRegistrationRepository.findByUsername(userId) ?: userRegistrationRepository.findByEmail(userId)
?: throw Exception("The user can't be deleted, because it doesn't exist")
user.username.let {
userRegistrationRepository.deleteByUsername(it)
}
}
}
我的存盤庫:
@Repository
interface UserRegistrationRepository: JpaRepository<User, String> {
fun findByUsername(username: String): User?
fun findByEmail(email: String): User?
fun deleteByUsername(username: String): Long
fun deleteByEmail(email: String): Long
}
我的擴展函式檔案(我把我的 Eencoder bean 放在這里):
fun UserRegistrationData.toPersistence() = User(
username = this.username,
encryptedPassword = this.encryptedPassword,
email = this.email,
name = this.name,
lastnames = this.lastnames,
roles = this.roles.map { it.toPersistence() }.toHashSet()
)
fun UserRole.toPersistence() = Role(
name = this.name
)
fun UserLoginDTO.maskPassword() = UserLoginDTO(
username = this.username,
password = "***********"
)
fun UserRegistrationDTO.confirmPassword() {
if (this.password != this.confirmPassword) throw ResponseStatusException(
HttpStatus.BAD_REQUEST,
"The passwords don't match"
)
}
fun UserRegistrationDTO.maskPassword() = UserRegistrationDTO(
username = this.username,
password = "***********",
confirmPassword = "***********",
email = this.email,
name = this.name,
lastnames = this.lastnames,
admin = this.admin,
contributor = this.contributor
)
fun UserRegistrationDTO.toDomain(): UserRegistrationData {
val user = UserRegistrationData(
name = this.name,
lastnames = this.lastnames,
email = this.email,
username = this.username,
encryptedPassword = passwordEncoder().encode(this.password),
roles = mutableListOf(UserRole.USER)
)
if(this.admin) user.roles.add(UserRole.ADMIN)
if(this.contributor) user.roles.add(UserRole.CONTRIBUTOR)
return user
}
@Bean
fun passwordEncoder(): PasswordEncoder {
return BCryptPasswordEncoder()
}
我的模型(它們并不都在同一個包中,這就是為什么有這么多模型):
data class UserRegistrationDTO(
val name: String? = null,
val lastnames: String? = null,
@field:NotBlank
val username: String,
@field:Email
val email: String,
@field:NotBlank
val password: String,
@field:NotBlank
val confirmPassword: String,
val admin: Boolean = false,
val contributor: Boolean = false
)
data class UserLoginDTO(
val username: String,
val password: String
)
data class UserRegistrationData(
val name: String? = null,
val lastnames: String? = null,
@field:NotBlank
val username: String,
@field:Email
val email: String,
@field:NotBlank
val encryptedPassword: String,
val roles: MutableList<UserRole> = mutableListOf(UserRole.USER)
)
class User(
@Id
var username: String,
@Column
var email: String,
@Column
var name: String?,
@Column
var lastnames: String?,
@Column
var encryptedPassword: String,
@OneToMany
@JoinTable(
name = "user_has_roles",
joinColumns = [JoinColumn(name = "user_username")],
inverseJoinColumns = [JoinColumn(name = "roles_name")]
)
var roles: Set<Role>? = null
)
And finally my Postman Request
If there's any more information that you need, please let me know.
uj5u.com熱心網友回復:
您遇到的問題是因為您混淆了BCryptPasswordEncoder#matches函式的輸入。
您的錯誤訊息將我指向源代碼中的這一行,這讓我暗示出了什么問題。閱讀源代碼是找出問題所在的好方法。
api 告訴我們,matches(CharSequence rawPassword, String encodedPassword)你給它編碼作為原始,原始作為編碼。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/337281.html
標籤:mysql spring-boot kotlin spring-security bcrypt
下一篇:想要模擬屬于另一個類的依賴項
