Christoph
Christoph

Reputation: 5

Spring Data Rest ID conversion using HashIDs

We have a concern exposing internal IDs to the outside world. Therefore I'm thinking about using a hashing mechanism (current choice is hashids) to hash our IDs.

I tried to use a @JsonSerializer and @JsonDeserializer mapping on the Entities ID field. But this only takes effect when including the ID in the body, and has no impact on the IDs in the URL paths.

Is there a possibility to do this, e.g. something like an ID Translation SPI?

Upvotes: 0

Views: 1952

Answers (4)

ranma2913
ranma2913

Reputation: 1206

Possibly look at https://github.com/fehnomenal/hashids-spring-boot-starter

public class UserModel {
    @Hashids(salt = "abc", minHashLength = 8, alphabet = "abcdefghijklmnopqrstuvwxyz")
    public long id;
    public String name;
}

Upvotes: 0

Fambo
Fambo

Reputation: 96

You could try using a converter.

@Component
@AllArgsConstructor
public class HashIdConverter implements Converter<String, Long> {

    private final HashidsUtil hashidsUtil;

    @Override
    public Long convert(@NonNull String source) {
        return hashidsUtil.decodeId(source);
    }
}

Using it the way I just showed you is a bit unsafe, but it can do the work quite well if you are careful enough

Upvotes: 0

Cepr0
Cepr0

Reputation: 30439

What you need is working "right from the box" in Spring Data REST by customizing item resource URIs:

@Configuration
public class RestConfigurer extends RepositoryRestConfigurerAdapter {

    @Override
    public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
        config.withEntityLookup().forRepository(ModelRepo.class, model -> HashIdUtil.encode(model.getId()), ModelRepo::findByEncodedId);
        super.configureRepositoryRestConfiguration(config);
    }
}
public interface ModelRepo extends JpaRepository<Model, Long> {

    default Model findByEncodedId(String encodedId) {
        return getById(HashIdUtil.decode(encodedId));
    }

    Model getById(Long id);
}
public class HashIdUtil {

    private static final Hashids HASHIDS = new Hashids("salt", 8);

    public static String encode(Long source) {
        return HASHIDS.encode(source);
    }

    public static Long decode(String source) {
        return HASHIDS.decode(source)[0];
    }
}

Unfortunately, due to the bug (I suppose), PUT/PATCH-ing entities does not work in Spring Boot 2+, unlike the previous version of SB (1.5+) where it works as expected.

See my demo: sdr-hashids-demo

Upvotes: 0

Konrad Botor
Konrad Botor

Reputation: 5063

The only thing I can think of is to create a request filter that would take the request with encoded ID in URL, then decode the ID and redirect to an URL with decoded ID.

Upvotes: 0

Related Questions