代码量:
技术栈:
源码地址:
数据库:MySQL + MongoDB + Redis
后端:IDEA
前端:微信小程序开发工具 + HBuilderX
虚拟机:VirtualBox,Linux系统采用CentOS
利用Maven创建Spring Boot项目
配置MySQL、MongoDB、Redis数据源
整合SSM框架
自定义异常类和封装结果集
集成Swagger,便于调用测试Web方法
配置后端验证功能
抵御跨站脚本XSS攻击
XSS攻击通常指的是通过利用网页开发时留下的漏洞,通过巧妙的方法注入恶意指令代码到网页,使用户加载并执行攻击者恶意制造的网页程序。这些恶意网页程序通常是JavaScript,但实际上也可以包括Java、 VBScript、ActiveX、 Flash 或者甚至是普通的HTML。攻击成功后,攻击者可能得到包括但不限于更高的权限(如执行一些操作)、私密网页内容、会话和cookie等各种内容。
比如用户在发帖或注册时,文本框中输入<script>alert(123)</script>
,如果不经过转义,保存到数据库里后,将来渲染时会执行该代码。
所以最有效的办法就是将用户输入的数据进行转义。
如果重写HttpServletRequest
类,需要覆盖的方法太多,非常耗时。
只需继承HttpServletRequestWrapper
类,该方法为请求传入包装类,采用装饰器模式,可以随意修改其中的方法。
package com.example.emos.wx.config.xss;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HtmlUtil;
import cn.hutool.json.JSONUtil;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* @author 袁梦达 2019012364
*/
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
public XssHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
}
@Override
public String getParameter(String name) {
String value = super.getParameter(name);
if(!StrUtil.hasEmpty(value)){
value = HtmlUtil.filter(value);
}
return value;
}
@Override
public String[] getParameterValues(String name) {
String[] values = super.getParameterValues(name);
if(values != null){
for(int i = 0; i < values.length; i++){
String value = values[i];
if(!StrUtil.hasEmpty(value)){
value = HtmlUtil.filter(value);
}
values[i] = value;
}
}
return values;
}
@Override
public Map<String, String[]> getParameterMap() {
Map<String, String[]> parameters = super.getParameterMap();
Map<String, String[]> map = new LinkedHashMap<>();
if(parameters != null){
for (String key : parameters.keySet()) {
String[] values = getParameterValues(key);
for(int i = 0; i < values.length; i++){
String value = values[i];
if(!StrUtil.hasEmpty(value)){
value = HtmlUtil.filter(value);
}
values[i] = value;
}
map.put(key, values);
}
}
return map;
}
@Override
public String getHeader(String name) {
String value = super.getHeader(name);
if(!StrUtil.hasEmpty(value)){
value = HtmlUtil.filter(value);
}
return value;
}
@Override
public ServletInputStream getInputStream() throws IOException {
InputStream in = super.getInputStream();
StringBuffer body = new StringBuffer();
InputStreamReader reader = new InputStreamReader(in, Charset.forName("UTF-8"));
BufferedReader buffer = new BufferedReader(reader);
String line = buffer.readLine();
while (line != null){
body.append(line);
line = buffer.readLine();
}
buffer.close();
reader.close();
in.close();
Map<String, Object> map = JSONUtil.parseObj(body.toString());
Map<String, Object> resultMap = new LinkedHashMap<>();
for (String key : map.keySet()) {
Object val = map.get(key);
if(map.get(key) instanceof String){
resultMap.put(key, HtmlUtil.filter(val.toString()));
}else {
resultMap.put(key, val);
}
}
String str = JSONUtil.toJsonStr(resultMap);
ByteArrayInputStream bain = new ByteArrayInputStream(str.getBytes());
return new ServletInputStream() {
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
}
@Override
public int read() throws IOException {
return bain.read();
}
};
}
}
只定义该类还不够,必须写一个过滤器,让用户的请求是经过这个wrapper类,而不是正常的request方法
package com.example.emos.wx.config.xss;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* @author 袁梦达 2019012364
*/
@WebFilter(urlPatterns = "/*")
public class XssFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
XssHttpServletRequestWrapper wrapper = new XssHttpServletRequestWrapper((HttpServletRequest) servletRequest);
filterChain.doFilter(wrapper, servletResponse);
}
@Override
public void destroy() {
}
}
整合shiro和jwt
shiro是进行认证与授权的框架,jwt是用来生成、验证token的
刷新token
客户端和服务端存一样的token,服务端的有效时间是客户端的2倍,当客户端的token过期后,去服务端的redis中查找token是否过期,如果还未过期,则生成新的token;如果服务端的token也过期,那么就要让用户重新登录
如何将员工账户和微信账号绑定
开通对象云存储服务
实现首页部分功能
设计人脸签到页面
业务流程:拍照–>保存图片–>隐藏摄像区–>显示图片–>点击签到
一开始照片是隐藏的,当点击拍照后,照片显示出来,摄像区隐藏,然后拍照按钮变为签到按钮
微信小程序提供标签来调用系统相机,调用相机对象的takePhoto()方法即可拍照
缓存系统常量数据
sys_config数据表中保存了一些常量配置信息,如:考勤几点开始,几点结束等。需要在springboot启动时加载,缓存成java对象,全局都可以使用
流程:读取表得到一个list集合,封装了常量的名字和对应的值,然后遍历这个集合,对集合中每一个对象(有键值对),获取键和值,然后通过反射将常量类对应的变量(即键)加载,然后赋值
查询当前时刻是否可以签到
流程:
实现shiro认证与授权
认证:从token中获取userId,然后查询数据库中是否有该用户,如果有的话将user对象,token等添加到info里返回
授权:从认证后的对象中获取user对象,然后获取userId,根据userId在数据库中查找拥有的权限集合,添加到Info中返回。
如果某个web方法需要用户具有相关权限,则加上@RequiresPermissions注解即可