spring boot使用自定义过滤器实现接口认证
自定义过滤器
创建MyFilter 类 去实现Filter接口
根据业务逻辑,来覆写doFilter方法
import com.alibaba.fastjson.JSONObject;
import com.shxp.project.common.entity.R;
import com.shxp.project.common.entity.SpringBeanFactoryUtils;
import org.springframework.beans.factory.annotation.Autowired;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
public class MyFilter implements Filter {
final static org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(MyFilter.class);
@Autowired
private CipherFilter cipherFilter;
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
// 打印请求信息
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
logger.info("------------- LogFilter 开始 -------------");
logger.info("请求地址: {} {}", request.getRequestURL().toString(), request.getMethod());
logger.info("远程地址: {}", request.getRemoteAddr());
long startTime = System.currentTimeMillis();
// 验证是否成功默认false
boolean isFilter = false;
// new一个报错返回实体
R r = new R();
try {
// 判断引入的验证方法是否为空,如果为空通过SpringBean的方式引进
if (cipherFilter == null) {
cipherFilter = SpringBeanFactoryUtils.getBean(CipherFilter.class);
}
// 验证方法
isFilter = cipherFilter.handle(request, response);
} catch (Exception ex) {
// e.printStackTrace();
r.setCode(500);
r.setMsg(ex.getMessage());
PrintWriter writer = null;
OutputStreamWriter osw = null;
try {
osw = new OutputStreamWriter(response.getOutputStream(), "UTF-8");
writer = new PrintWriter(osw, true);
String json = JSONObject.toJSONString(r);
writer.write(json);
writer.flush();
writer.close();
osw.close();
} catch (UnsupportedEncodingException e) {
logger.error("过滤器返回信息失败:" + e.getMessage(), e);
} catch (IOException e) {
logger.error("过滤器返回信息失败:" + e.getMessage(), e);
} finally {
if (null != writer) {
writer.close();
}
if (null != osw) {
osw.close();
}
}
return;
}
logger.info("------------- LogFilter 结束 耗时:{} ms -------------", System.currentTimeMillis() - startTime);
// 如果验证通过执行
if (isFilter) {
chain.doFilter(req, res);
}
}
public void init(FilterConfig filterConfig) {
}
public void destroy() {
}
}
创建FilterConfig类
该配置类用于配置你要过滤的过滤路径
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration //定义此类为配置类,必须增加
public class FilterConfig {
@Bean
public FilterRegistrationBean myFilterRegistrationBean() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new MyFilter());
//添加过滤器路径
filterRegistrationBean.addUrlPatterns("/workflow/*");
filterRegistrationBean.addUrlPatterns("/system/yyxt/*");
// filterRegistrationBean.addUrlPatterns("/login/*");
return filterRegistrationBean;
}
}
加密 解密 验证CipherFilter
CipherFilter 中主要对过滤接口Header中的值进行:非空判断、数据解密、数据认证
public boolean handle(HttpServletRequest request, HttpServletResponse response) throws Exception {
AuthParam authorityParam = new AuthParam();
authorityParam.setModuleId(request.getHeader("moduleId"));
authorityParam.setNonce(request.getHeader("nonce"));
authorityParam.setSignature(request.getHeader("signature"));
return handle0(authorityParam);
}
public boolean handle0(AuthParam authorityParam) throws Exception {
String moduleId = authorityParam.getModuleId();
if (StringUtils.isBlank(moduleId)) {
throw new Exception("moduleId 不允许为空!");
}
// 查询所有外部对接系统信息
Map<String, SysYyxtVo> map = subSystemService.getSubSystemMap();
SysYyxtVo subSystem = map.get(moduleId);
if (subSystem == null) {
throw new Exception("无法识别的moduleId !");
}
String nonce = authorityParam.getNonce();
if (StringUtils.isBlank(nonce)) {
throw new Exception("nonce 不允许为空!");
}
String signature = authorityParam.getSignature();
if (StringUtils.isBlank(signature)) {
throw new Exception("signature 不允许为空!");
}
// 对数据进行加密判断是否一致
// moduleKey 是本系统对外部系统的密钥
String sig2 = AESUtils.sha1(subSystem.getModulekey(), nonce);
if (!signature.equals(sig2)) {
throw new Exception("验证不通过,请检查是否持有正确的moduleKey!");
}
return true;
}
其他工具类
AES 128 加密工具
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.util.Base64Utils;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.UUID;
/**
* AES 128 加密工具
*/
public class AESUtils {
public final static String ENCODING="UTF-8";
public final static String KEY_AES="AES";
public static KeyGenerator kgen;
static {
try {
kgen = KeyGenerator.getInstance("AES");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
/**
* AES128 加密
* @param content 内容
* @param password 密钥
* @return 加密后的结果
*/
public static String aes128Encrypt(String content, String password){
try{
Cipher cipher = Cipher.getInstance(KEY_AES);
byte[] byteContent = content.getBytes(ENCODING);
SecretKeySpec secretKeySpec = getSecretKeySpec(password);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
byte[] result = cipher.doFinal(byteContent);
return Base64Utils.encodeToString(result);
}catch (Exception e){
e.printStackTrace();
}
return null;
}
/**
* AES128 解密
* @param content 内容
* @param password 密钥
* @return 解密后的结果
*/
public static String aes128Decrypt(String content, String password){
try{
Cipher cipher = Cipher.getInstance(KEY_AES);
SecretKeySpec secretKeySpec = getSecretKeySpec(password);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
byte[] byteContent = Base64Utils.decodeFromString(content);
byte[] result = cipher.doFinal(byteContent);
return new String(result,ENCODING);
}catch (Exception e){
e.printStackTrace();
}
return null;
}
private static SecretKeySpec getSecretKeySpec(String password) throws UnsupportedEncodingException {
kgen.init(128, new SecureRandom(password.getBytes(ENCODING)));
return new SecretKeySpec(kgen.generateKey().getEncoded(), KEY_AES);
}
public static String md5(String text, String key) throws Exception{
String encodeStr = DigestUtils.md5Hex(text + key);
return encodeStr;
}
public static String sha1(String text, String key) throws Exception{
String encodeStr = DigestUtils.sha1Hex(text + key);
return encodeStr;
}
}
bean未加载前获取bean
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
* bean未加载前获取bean
*/
@Component
public class SpringBeanFactoryUtils implements ApplicationContextAware {
private static ApplicationContext context = null;
//获取bean
public static <T> T getBean(Class<T> type) {
return context.getBean(type);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if (SpringBeanFactoryUtils.context == null) {
SpringBeanFactoryUtils.context = applicationContext;
}
}
}
接口效果
swagger访问
我们发现通过swagger访问已经不行了
Apipost 错误请求
我们用apipost 故意写错moduleId