当前位置: 首页 > 知识库问答 >
问题:

Spring验证:由于密码编码,@Pattern的ConstraintViolationException

单于皓轩
2023-03-14

我只是在实现一个基本的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)
}

共有1个答案

周意智
2023-03-14

问题是,您在控制器中使用的实体与在服务中使用的实体相同。因此,在控制器中,它的工作方式与您预期的一样。但在服务中,你用加密的密码更新未加密的密码,并将其保存到数据库中。保存到数据库时,也会检查验证注释,从而触发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的一部分进行身份验证?请注意,我不是在谈论单点登录,只是想要用户名/密码的身份验证。 谢谢,

  • 所以问题是:应该如何正确验证密码?