我应该如何使用Spring Data REST自动编码我的实体的已提交的纯密码字段?
我正在使用BCrypt编码器,当客户端通过POST,PUT和PATCH发送请求时,我想自动对请求的密码字段进行编码。
@Entity
public class User {
@NotNull
private String username;
@NotNull
private String passwordHash;
...
getters/setters/etc
...
}
首先,我尝试使用@HandleBeforeCreate和@HandleBeforeSave事件侦听器解决问题,但是其中的User已经合并,所以我不能在User的新密码或旧的passwordHash之间进行任何区别。
@HandleBeforeSave
protected void onBeforeSave(User user) {
if (user.getPassword() != null) {
account.setPassword(passwordEncoder.encode(account.getPassword()));
}
super.onBeforeSave(account);
}
可以在setter方法上使用@Projection和SpEL吗?
您可以实现Jackson JsonDeserializer:
public class BCryptPasswordDeserializer extends JsonDeserializer<String> {
public String deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
ObjectCodec oc = jsonParser.getCodec();
JsonNode node = oc.readTree(jsonParser);
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
String encodedPassword = encoder.encode(node.asText());
return encodedPassword;
}
}
并将其应用于您的JPA Entity属性:
// The value of the password will always have a length of
// 60 thanks to BCrypt
@Size(min = 60, max = 60)
@Column(name="password", nullable = false, length = 60)
@JsonDeserialize(using = BCryptPasswordDeserializer.class )
private String password;
修改密码字段的设置方法已足够,如下所示:
public void setPassword(String password) {
PasswordEncoder encoder = new BCryptPasswordEncoder();
this.password = encoder.encode(password);
}
对@robgmills JsonDeserializer
解决方案的一些增强:
DelegatingPasswordEncoder
。它更灵活,请参见spring docs。PasswordEncoder
。JsonDeserializer
可能不止一个-更好地使其成为内部类。@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
对于Spring Boot代码,看起来像:
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
public static final PasswordEncoder PASSWORD_ENCODER = PasswordEncoderFactories.createDelegatingPasswordEncoder();
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService()).passwordEncoder(PASSWORD_ENCODER);
}
....
public class JsonDeserializers {
public static class PasswordDeserializer extends JsonDeserializer<String> {
public String deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
ObjectCodec oc = jsonParser.getCodec();
JsonNode node = oc.readTree(jsonParser);
String rawPassword = node.asText();
return WebSecurityConfig.PASSWORD_ENCODER.encode(rawPassword);
}
}
...
@Entity
public class User ...
@Column(name = "password")
@Size(max = 256)
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
@JsonDeserialize(using = JsonDeserializers.PasswordDeserializer.class)
private String password;
...