我只是在实现一个基本的CRUD服务,用户可以在数据库中创建,其密码与特定的正则表达式匹配,并使用BCryptPasswordEncoder
进行编码。
我的测试失败,因为密码上有一个ConstraintViolationException
,表示它不满足regex要求:
javax.validation.ConstraintViolationException: Validation failed for classes [com.hoaxify.hoaxify.user.User] during persist time for groups [javax.validation.groups.Default, ]
List of constraint violations:[
ConstraintViolationImpl{interpolatedMessage='must match "^(?=.*[a-z])(?=.*\d)(?=.*[A-Z]).{8,50}$"', propertyPath=password, rootBeanClass=class com.hoaxify.hoaxify.user.User, messageTemplate='{javax.validation.constraints.Pattern.message}'}
它没有陷入我的@ExceptionHandler
,因为它抛出了一个ConstraintViolationExc0019
,而不是一个MultiodArgumentNotValidExc0019
。我调试并发现,当它试图匹配给定的正则表达式时,密码本身的值显示为:$2a10$pmRUViwj3Ey4alK0eqT1Dulz4BpGSlSReHyBR28K6bIE4。LZ7nYWG
而被传递的密码是:P4sword
因此,验证似乎是在加密密码而不是原始密码上运行的。我认为验证应该在createUser
方法中接收的对象上进行,然后再进行任何其他操作。
任何关于为什么会发生这种情况以及如何修复的帮助都将不胜感激。
@RestController
@RequestMapping("{my/path}")
class UserController {
@Autowired
lateinit var userService: UserService
@PostMapping
fun createUser(@Valid @RequestBody user: User): GenericResponse {
userService.save(user)
return GenericResponse("Saved user")
}
@ExceptionHandler(MethodArgumentNotValidException::class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
fun handleValidationException(exception: MethodArgumentNotValidException, request: HttpServletRequest): ApiError {
val error = ApiError(400, "Validation error", request.servletPath)
val bindingResult = exception.bindingResult
bindingResult.fieldErrors.forEach {
error.validationErrors[it.field] = it.defaultMessage ?: "invalid"
}
return error
}
}
@Entity
class User(
@Id
@GeneratedValue
val id: Long,
@field:NotBlank
@field:Size(min = 4, max = 50)
var username: String,
@field:NotBlank
@field:Size(min = 4, max = 50)
var displayName: String,
@field:NotBlank
@field:Pattern(regexp = """^(?=.*[a-z])(?=.*\d)(?=.*[A-Z]).{8,50}$""")
var password: String
)
@Service
class UserService(
private val userRepository: UserRepository,
private val passwordEncoder: BCryptPasswordEncoder = BCryptPasswordEncoder()
) {
fun save(user: User): User {
user.password = passwordEncoder.encode(user.password)
return userRepository.save(user)
}
}
(有关测试)
@Test
fun postUser_whenUserIsValid_receiveOk() {
val user = User(
0,
"test-user",
"test-display",
"P4ssword"
)
val response: ResponseEntity<Any> = testRestTemplate.postForEntity(API_USERS_BASE, user, Any::class.java)
assertThat(response.statusCode).isEqualTo(HttpStatus.OK)
}
问题是,您在控制器中使用的实体与在服务中使用的实体相同。因此,在控制器中,它的工作方式与您预期的一样。但在服务中,你用加密的密码更新未加密的密码,并将其保存到数据库中。保存到数据库时,也会检查验证注释,从而触发ConstraintViolationException
。
最好的选择是为控制器创建一个单独的对象。例如,创建一个类似于User
实体的CreateUserRequest
类,但只包含控制器需要的字段。您可以在那里添加验证注释。然后在服务中,将CreateUserRequest
实例转换为User
实体。在用户类上,删除@模式
验证,因为您不想验证加密的密码。
问题内容: 我正在创建用于密码验证的正则表达式,以在Java应用程序中用作配置参数。 regexp是: 密码策略为: 至少8个字符 包含至少一位数字 包含至少一个较低的alpha字符和一个较高的alpha字符 在一组特殊字符(@#%$^等)中包含至少一个字符 不包含空格,制表符等。 我只缺少第5点。我无法进行正则表达式检查空间,制表符,回车等。 有人可以帮我吗? 问题答案: 尝试这个: 说明: 由
问题内容: 因此,我必须创建验证密码是否有效的代码: 至少8个字符长 包含至少1个数字 包含至少1个大写字母 这是代码: 我不确定出什么问题,但是当我输入带有数字的密码时-它会一直告诉我我需要一个带有数字的密码。有什么办法吗? 问题答案: 您可以将模块用于正则表达式。 有了它,您的代码将如下所示:
主要内容:使用方式,实例演示jQuery Password Validation(密码验证)插件扩展了 jQuery Validate 插件,提供了两种组件: 一种评价密码的相关因素的功能:比如大小写字母的混合情况、字符(数字、特殊字符)的混合情况、长度、与用户名的相似度(可选的)。 一种使用评价功能显示密码强度的验证插件自定义方法。显示的文本可以被本地化。 您可以简单地自定义强度显示的外观、本地化消息显示,并集成到已有的表
我试图为我用JavaScript制作的密码验证程序开发一个regex表达式。 要求 null
我知道SAML是如何用于单点登录(SSO)的。也就是说,从SP重定向到IDP,并从SAML响应/断言获取用户身份。 我的问题是-SAML 2.0规范是否定义了如何将用户名和密码作为SAML请求xml的一部分进行身份验证?请注意,我不是在谈论单点登录,只是想要用户名/密码的身份验证。 谢谢,
所以问题是:应该如何正确验证密码?