项目背景:
公司想要一个系统去收集各个部门都是使用了哪些中间件,该系统分期,每期都会下发任务表单。
场景1:发布表单
case0:直接分享表单的key。
如果是点击url会直接根据url的表单key查询表单详情
case1:分享url先base64加密再aes加密
问题1:浏览器会自动解码,将“+”号解码为null
解决方案:1.通过提前对字符编码再传输参数2.改变请求方式,content-type:的值。3.用框架
base64:
// java url安全的Base64编码
String urlSafeEncodeResult = Base64.getUrlEncoder().encodeToString(bytes);
byte[] urlSafeDecodeResult = Base64.getUrlDecoder().decode(urlSafeEncodeResult);
Base64从本质来说一种编码方式,分片一系列操作后,后根据Base64编码表,获取相应的编码值
AES:
对称加密(对称加密算法也就是加密和解密用相同的密钥)
对称加密算法与非对称加密算法的区别:
(1)对称加密算法:加密和解密用到的密钥是相同的,这种加密方式加密速度非常快,适合经常发送数据的场合。缺点是密钥的传输比较麻烦。
(2)非对称加密算法:加密和解密用的密钥是不同的,这种加密方式是用数学上的难解问题构造的,通常加密解密的速度比较慢,适合偶尔发送数据的场合。优点是密钥传输方便。常见的非对称加密算法为RSA。
有加密向量vi每次都会传递vi过去。提交后会做数据校验,说穿了就是看当前表单是不是当前登陆人部门的。 url:部门id+vi。
场景2:新增功能,停止发布,微信公众号
case0:(新增发布与停止发布功能)/+(SpringBoot+Websokect实现微信扫码自动登录)(开通公众号)+URL分享
新增发布与停止发布功能
发布:先传递一个表单的可以过来,再权限校验(当前登陆人是否是超管,是否是所有者),再检查当前表单是否存在,不存在直接报错,存在进行状态的更新为(收集中) 发布:先传递一个表单的可以过来,再权限校验(当前登陆人是否是超管,是否是所有者),进行状态的更新为(停止)
停止任务时,表单的发布也需要一起停止。
SpringBoot+Websokect实现微信扫码自动登录
1.登录公众号后台,配置接入URL和Token等
2.导入微信的jar包与yml配置
导入微信的jar包
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-mp</artifactId>
<version>${weixin-java.version}</version>
</dependency>
yml配置
wx:
mp:
configs:
- appId: #公众号appId
secret: #公众号秘钥
token: dHClTzEAc*******
aesKey: 3aNsbtc8wdx92M14******
3.通过@ConfigurationProperties将yml注入
4.接入公众号
其实本质就是调用微信jar包提供的方法去做一些判空和非法参数校验
5.编写扫码事件
6.websocket常量、WebsocketConfig核心配置类、WebSocketService缓存存储
websocket:stomp端点地址、订阅地址 WebsocketConfig:注册stomp端点,配置消息代理 WebSocketService:内存存储可用redis代替,将webSocket的token与http的认证token绑定在一起,这样便可以互相都找的到了,推送成功后移除。
场景3:XSS过滤处理(HttpServletRequestWrapper原理+HTMLfilter)
技术因素:HttpServletRequest没有提供set方法对前端参数进行修改,但是实际开发时需要过滤xss,所以HttpServletRequest就因势而生。
HttpServletRequestWrapper原理:采用装饰者模式模式对HttpServletRequest进行包装,通过继承HttpServletRequestWrapper 类去重写getParameterValues,getParameterh和获取原始的请求等方法, 实际还是调用HttpServletRequest的相对应方法,但是可以对方法的结果进行改装。
HTMLfilter:我也没看懂具体原理是撒,有懂个可以说一下。
代码展示:
public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper {
//html过滤
private final static HTMLFilter htmlFilter = new HTMLFilter();
//没被包装过的HttpServletRequest(特殊场景,需要自己过滤)
HttpServletRequest orgRequest;
@Getter
private String bodyJson;
public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
orgRequest = request;
}
/**
* 获取最原始的request
*/
public static HttpServletRequest getOrgRequest(HttpServletRequest request) {
if (request instanceof BodyReaderHttpServletRequestWrapper) {
return ((BodyReaderHttpServletRequestWrapper) request).getOrgRequest();
}
return request;
}
@Override
public ServletInputStream getInputStream() throws IOException {
if (!MediaType.APPLICATION_JSON_VALUE.equalsIgnoreCase(super.getHeader(HttpHeaders.CONTENT_TYPE))) {
return super.getInputStream();
}
if (StrUtil.isBlank(bodyJson)) {
bodyJson = IOUtils.toString(super.getInputStream(), StandardCharsets.UTF_8);
}
final ByteArrayInputStream bis = new ByteArrayInputStream(bodyJson.getBytes(StandardCharsets.UTF_8));
return new ServletInputStream() {
@Override
public boolean isFinished() {
return true;
}
@Override
public boolean isReady() {
return true;
}
@Override
public void setReadListener(ReadListener readListener) {
}
@Override
public int read() throws IOException {
return bis.read();
}
};
}
@Override
public String getParameter(String name) {
String value = super.getParameter(xssEncode(name));
if (StrUtil.isNotBlank(value)) {
value = xssEncode(value);
}
return value;
}
@Override
public String[] getParameterValues(String name) {
String[] parameters = super.getParameterValues(name);
if (parameters == null || parameters.length == 0) {
return null;
}
for (int i = 0; i < parameters.length; i++) {
parameters[i] = xssEncode(parameters[i]);
}
return parameters;
}
//获取参数
@Override
public Map<String, String[]> getParameterMap() {
//用LinkedHashMap是因为有序
Map<String, String[]> map = new LinkedHashMap<>();
//调用this.request.getParameter(name),其实就是调用ServletRequest的getParameterMap();
Map<String, String[]> parameters = super.getParameterMap();
// 通过hashMap得到key,通过key,再得到value参数
for (String key : parameters.keySet()) {
String[] values = parameters.get(key);
for (int i = 0; i < values.length; i++) {
//将每个参数传递给hutool的HTMLFilter,进行xss过滤
values[i] = xssEncode(values[i]);
}
map.put(key, values);
}
return map;
}
@Override
public String getHeader(String name) {
String value = super.getHeader(xssEncode(name));
if (StrUtil.isNotBlank(value)) {
value = xssEncode(value);
}
return value;
}
private String xssEncode(String input) {
return htmlFilter.filter(input);
}
/**
* 获取最原始的request
*/
public HttpServletRequest getOrgRequest() {
return orgRequest;
}
}