在SQL Server 2012数据库中,我有一个带有varbinary(128)列的表,该列存储由证书(AppCert)支持的密钥(Secret_Key)加密的数据和使用主键的SHA2_512哈希的身份验证器:
CREATE TABLE [Lookup].[SecretStuff] (
[Id] tinyint NOT NULL,
[Secret] varbinary(128) NOT NULL
CONSTRAINT [PK_Lookup-SecretStuff_Id] PRIMARY KEY CLUSTERED ([Id] ASC),
CONSTRAINT [UN_Lookup-SecretStuff_Secret] UNIQUE NONCLUSTERED ([Secret])
);
OPEN SYMMETRIC KEY [Secret_Key] DECRYPTION BY CERTIFICATE [AppCert];
INSERT INTO [Lookup].[SecretStuff] ([Id], [Secret]) VALUES (1, ENCRYPTBYKEY(KEY_GUID('Secret_Key'), CONVERT(nvarchar(512), 'I have a secret'), 1, HASHBYTES('SHA2_512', CONVERT(varbinary(128), CONVERT(tinyint, 1)))));
CLOSE SYMMETRIC KEY [Secret_Key];
OPEN SYMMETRIC KEY [Secret_Key] DECRYPTION BY CERTIFICATE [AppCert];
SELECT [Id], CONVERT(nvarchar, DECRYPTBYKEY([Secret], 1, HASHBYTES('SHA2_512', CONVERT(varbinary, [Id])))) AS [Secret] FROM [Lookup].[SecretStuff];
CLOSE SYMMETRIC KEY [Secret_Key];
这一切都很美妙。现在,我有一个使用JPA / Hibernate的Spring Boot应用程序,它连接并经过测试/验证,可以使用这个数据库。 SecretStuff类:
@Entity
@Table(name="SecretStuff", schema="Lookup")
public class SecretStuff {
@Id
@Column(name = "Id",
nullable = false)
private Integer id;
@Column(name = "Secret",
nullable = false,
unique = true)
@Size(min = 1, max = 255)
@ColumnTransformer(
read = "CONVERT(nvarchar(89), DECRYPTBYKEY([Secret], 1,
HASHBYTES('SHA2_512', CONVERT(varbinary(128), [Id]))))")
private String secret;
// getters/setter omitted
}
当我测试SecretStuff类时,我看到以下Hibernate生成的SQL:
select
secretstuf0_.Id as Id1_7_0_,
CONVERT(nvarchar(89), DECRYPTBYKEY(secretstuf0_.[Secret],
1,
HASHBYTES('SHA2_512',
CONVERT(varbinary(128),
secretstuf0_.[Id])))) as Secret2_7_0_
from
Lookup.SecretStuff secretstuf0_
where
secretstuf0_.Id=?
完全合理的查询,执行并返回Id = 1 Secret = NULL的1行,因为在执行查询之前未打开SYMMETRIC KEY。
我的问题: 如何在查询之前的同一事务中执行OPEN SYMMETRIC KEY ...命令,并在查询后的同一事务中执行CLOSE SYMMETRIC KEY ...命令?
我在服务类方法中使用了Hibernate.initialize来对事务内部的懒惰提取到多个关系。我会在这里使用类似的方法吗?怎么样?
我在输入这个问题时看到了this article,但它已经有几年的历史了,并且使用了NativeQuery的EntityManager方法。是否有更新的方法来管理JPA / Hibernate?
答案 0 :(得分:1)
虽然不是我想要的确切解决方案,article I referenced in my original question和@TrevorAbell的一些帮助使我得到了以下代码,这似乎符合我的需要。我在这里发布,以防其他人正在寻找类似的解决方案。我仍然愿意接受其他解决方案。
密钥是使用EntityManager在查询周围运行SYMMETRIC KEY命令。我将包含@Repository接口和@Service类以获得完整性,但关键是@Service类:
@Repository
public interface SecretStuffRepository extends JpaRepository<SecretStuff, Integer> {}
@Service
@Transactional(readOnly = true)
public class SecretStuffService {
@PersistenceContext
private EntityManager entityManager;
@Autowired
private SecretStuffRepository repository;
public Iterable<SecretStuff> findAll() {
this.entityManager.createNativeQuery("
OPEN SYMMETRIC KEY [Secret_Key]
DECRYPTION BY CERTIFICATE [AppCert];
").executeUpdate();
Iterable<SecurityQuestion> questions = this.repository.findAll();
this.entityManager.createNativeQuery("
CLOSE SYMMETRIC KEY [Secret_Key];
").executeUpdate();
return stuff;
}
}
现在,当我测试SecretStuffService时,我看到以下Hibernate生成的SQL:
Hibernate:
OPEN SYMMETRIC KEY [Secret_Key] DECRYPTION
BY
CERTIFICATE [AppCert];
Hibernate:
select
secretstuf0_.Id as Id1_5_0_,
CONVERT(nvarchar(89),
DECRYPTBYKEY(secretstuf0_.[Secret],
1,
HASHBYTES('SHA2_512',
CONVERT(varbinary(128),
secretstuf0_.[Id])))) as Secret2_5_0_
from
Lookup.SecretStuff secretstuf0_
where
secretstuf0_.Id=?
Hibernate:
CLOSE SYMMETRIC KEY [Secret_Key];
调用SecretStuffService.findAll()现在打开密钥,调用存储库findAll()方法,并关闭同一事务中的密钥。请记住,在这种情况下,NativeQuery特定于Microsoft SQL Server,因此您需要将适当的命令替换为您的数据库供应商。