mat*_*boy 5 session session-variables redis spring-boot spring-session
我正在使用Spring Boot 1.3.3来构建 Web 应用程序。我使用Redis来处理会话。
我会将一些“关键”数据设置到 中HttpSession,我想了解这将如何与 Redis 配合使用。是服务器端存储的信息加上浏览器端的密钥还是所有数据都在用户浏览器的cookie中?
我想查看答案的文档参考或获得权威答案(例如 Pivotal dev)。
虽然我同意这里其他答案所说的大部分内容,但其他答案都没有真正回答这个问题。我假设您在 Spring Boot 中将 SpringSession 与 Redis 结合使用。
为了使用 SpringSession,您可能已经(直接或间接)配置了一个扩展的 servlet 过滤器SessionRepositoryFilter。
SessionRepositoryFilter 使用SessionRepository. 由于您使用的是 Redis,因此您的配置很可能使用RedisOperationsSessionRepository.
RedisOperationsSessionRepository实现SessionRepository,正如您可能已经猜到的那样,最终负责根据密钥(在您的情况下,可能作为 cookie 存储在用户浏览器上的密钥)获取、存储和删除会话。
RedisOperationSessionRepository默认情况下,使用JdkSerializationRedisSerializer实现 的RedisSerializer来序列化会话数据,然后再将所述数据交给 Redis。
根据 的文档RedisOperationSessionRepository,可以RedisOperationSessionRepository通过它的 setDefaultSerializer方法设置将使用的默认序列化器。
理论上,您可以在那里扩展JdkSerializationRedisSerializer并执行加密和解密。JdkSerializationRedisSerializer看起来像这样:
public class JdkSerializationRedisSerializer implements RedisSerializer<Object> {
private Converter<Object, byte[]> serializer = new SerializingConverter();
private Converter<byte[], Object> deserializer = new DeserializingConverter();
public Object deserialize(byte[] bytes) {
if (SerializationUtils.isEmpty(bytes)) {
return null;
}
try {
return deserializer.convert(bytes);
} catch (Exception ex) {
throw new SerializationException("Cannot deserialize", ex);
}
}
public byte[] serialize(Object object) {
if (object == null) {
return SerializationUtils.EMPTY_ARRAY;
}
try {
return serializer.convert(object);
} catch (Exception ex) {
throw new SerializationException("Cannot serialize", ex);
}
}
}
Run Code Online (Sandbox Code Playgroud)
因此,添加加密的潜在方法可能如下所示:
@Component
@Qualifier("springSessionDefaultRedisSerializer") //SB 2.0.0+
public class CrypticRedisSerializer extends JdkSerializationRedisSerializer {
@Override
public Object deserialize(byte[] bytes) {
byte[] decrpyted;
try {
decrpyted = EncryptionUtils.decrypt(bytes);
return super.deserialize(decrpyted);
} catch (NoSuchPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (GeneralSecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// handle expections or allow to propagate, your choice!
return null;
}
@Override
public byte[] serialize(Object object) {
byte[] bytes = super.serialize(object);
try {
return EncryptionUtils.encrypt(bytes);
} catch (NoSuchPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (GeneralSecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// handle expections or allow to propagate, your choice!
return null;
}
}
Run Code Online (Sandbox Code Playgroud)
EncrpytionUtils 可能如下所示:
public class EncryptionUtils {
private static SecretKeySpec skeySpec;
static {
try {
ClassPathResource res = new ClassPathResource("key.key");
if(res != null){
File file = res.getFile();
FileInputStream input = new FileInputStream(file);
byte[] in = new byte[(int)file.length()];
input.read(in);
skeySpec = new SecretKeySpec(in, "AES");
input.close();
}
}catch (FileNotFoundException e) {
e.printStackTrace();
}catch (IOException e) {
e.printStackTrace();
}
}
public static byte[] encrypt(byte[] input)
throws GeneralSecurityException, NoSuchPaddingException{
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
return cipher.doFinal(input);
}
public static byte[] decrypt(byte[] input) throws GeneralSecurityException, NoSuchPaddingException{
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
return cipher.doFinal(input);
}
}
Run Code Online (Sandbox Code Playgroud)
要实现此功能,您所需要做的就是确保将自定义序列化器设置为RedisOperationSessionRepository用户的默认序列化器。
请注意:
要查看的文档和参考:
来自创建者或 redis 的关于 redis 安全性的非常好的文章 - http://antirez.com/news/96读起来非常有趣。也请阅读评论。
我很好奇的一件事是,您的“关键”数据是否必须存储在会话中?如果它对性能不是非常重要,您可以将其保存在数据库中。我在我们的产品中使用 Redis 只是为了存储令牌和基本用户数据,我看到人们将大数据转储为会话数据,这很好,但我认为这不是一个好主意。
| 归档时间: |
|
| 查看次数: |
1813 次 |
| 最近记录: |