在上一篇,安全传输敏感数据的最佳实践 (中),我们已经成功将加密数据解密,并赋值到参数上,接下我们就要加密数据,并返回给客户端。根据之前提到,加密数据就要用到客户端的公钥,我们怎么获取到客户端的公钥?
其实有很多种方法,在这里我提供我的实现方式。我们可以设置一个请求头X-JWE-CLIENT,然后再取出其中的值,在配置文件application.yaml中,各个客户端对应他的clientId和base64的公钥字符串,这样我们就能够根据请求头,去取出对应客户端的公钥进行加密。为了方便一键安装使用,封装了一个jwe-security-spring-boot-starter。
新建一个模块
package cn.sakka.jwe.security;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author sakka
* @version 1.0
* @description: jwe security 自动配置类
* @date 2023/4/5
*/
@ConditionalOnProperty(value = "jwe.security.enabled", havingValue = "true")
@Configuration
public class JweSecurityAutoConfiguration {
@Bean
public JweSecurityMappingJackson2HttpMessageConverter jweMappingJackson2HttpMessageConverter(@Autowired JweSecurityProperties jweSecurityProperties) {
return new JweSecurityMappingJackson2HttpMessageConverter(jweSecurityProperties);
}
@ConfigurationProperties(prefix = "jwe.security")
@Bean
public JweSecurityProperties jweSecurityProperties() {
return new JweSecurityProperties();
}
}
package cn.sakka.jwe.security;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* @author sakka
* @version 1.0
* @description: //TODO
* @date 2023/3/30
*/
@Target({
TYPE})
@Retention(RUNTIME)
public @interface JweSecurityEntity {
}
package cn.sakka.jwe.security;
public class JweSecurityException extends RuntimeException {
public JweSecurityException() {
}
public JweSecurityException(String message) {
super(message);
}
public JweSecurityException(String message, Throwable cause) {
super(message, cause);
}
public JweSecurityException(Throwable cause) {
super(cause);
}
public JweSecurityException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
主要多了writeInternal方法,该方法读取客户端公钥并进行加密,canWrite判断数据是否需要jwe加密
package cn.sakka.jwe.security;
import cn.hutool.core.codec