使用Spring Data REST进行密码编码

问题描述 投票:4回答:3

我应该如何使用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吗?

spring-data-rest
3个回答
8
投票

您可以实现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;

1
投票

修改密码字段的设置方法已足够,如下所示:

public void setPassword(String password) {
        PasswordEncoder encoder = new BCryptPasswordEncoder();
        this.password = encoder.encode(password);
    }

参考:https://github.com/charybr/spring-data-rest-acl/blob/master/bookstore/src/main/java/sample/sdr/auth/bean/UserEntity.java


0
投票

对@robgmills JsonDeserializer解决方案的一些增强:

  • [在Spring 5中引入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;
    ...
© www.soinside.com 2019 - 2024. All rights reserved.