前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >springboot+security 记录用户操作日志

springboot+security 记录用户操作日志

作者头像
用户5899361
发布2020-12-07 15:23:16
2.3K0
发布2020-12-07 15:23:16
举报
文章被收录于专栏:学习java的小白

数据库

代码语言:javascript
复制
SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for `sys_log`
-- ----------------------------
DROP TABLE IF EXISTS `sys_log`;
CREATE TABLE `sys_log` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `username` varchar(255) NOT NULL COMMENT '用户名',
  `operation` varchar(255) NOT NULL COMMENT '操作',
  `method` varchar(255) NOT NULL COMMENT '方法名',
  `params` varchar(255) DEFAULT NULL COMMENT '参数',
  `ip` varchar(255) DEFAULT NULL,
  `create_date` datetime NOT NULL COMMENT '操作时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of sys_log
-- ----------------------------
INSERT INTO `sys_log` VALUES ('1', 'admin', '登陆成功', 'login', null, '0:0:0:0:0:0:0:1', '2020-03-06 14:47:16');
INSERT INTO `sys_log` VALUES ('2', 'admin', '登陆成功', 'login', null, '0:0:0:0:0:0:0:1', '2020-03-06 14:54:09');
INSERT INTO `sys_log` VALUES ('3', 'admin', '登陆成功', 'login', null, '127.0.0.1', '2020-03-06 14:56:25');
INSERT INTO `sys_log` VALUES ('4', 'admin', '退出系统', 'loginout', null, null, '2020-03-06 14:56:27');

实体类

代码语言:javascript
复制
@Setter
@Getter
public class SysLog implements Serializable {
    private Long id;

    private String username; //用户名

    private String operation; //操作

    private String method; //方法名

    private String params; //参数

    private String ip; //ip地址

    private Date createDate; //操作时间

切面

切面中仅记录用户除登陆和退出以外的操作

代码语言:javascript
复制
import com.alibaba.fastjson.JSON;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;

/**
 * @ProjectName: 
 * @Package:  系统日志:切面处理类 切面只记录除登陆和退出的记录 登录退出日志在监听器中记录
 * @Author: huat
 * @Date: 2020/3/5 22:26
 * @Version: 1.0
 */
@Aspect
@Component
public class SysLogAspect {
    @Autowired
    private SysLogService sysLogService;

    //定义切点 @Pointcut
    //在注解的位置切入代码
    @Pointcut("@annotation( cn.bdqn.utils.MyLog)")
    public void logPoinCut() {
    }

    //切面 配置通知
    @AfterReturning("logPoinCut()")
    public void saveSysLog(JoinPoint joinPoint) {

        //保存日志
        SysLog sysLog = new SysLog();

        //从切面织入点处通过反射机制获取织入点处的方法
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        //获取切入点所在的方法
        Method method = signature.getMethod();

        //获取操作
        MyLog myLog = method.getAnnotation(MyLog.class);
        if (null!=myLog) {
            String value = myLog.value();
            sysLog.setOperation(value);//保存获取的操作
        }

        //获取请求的类名
        String className = joinPoint.getTarget().getClass().getName();
        //获取请求的方法名
        String methodName = method.getName();
        sysLog.setMethod(className + "." + methodName);

        sysLog.setCreateDate(new Date());
        //获取请求
        HttpServletRequest request = ((ServletRequestAttributes)
                RequestContextHolder.getRequestAttributes()).getRequest();
        //获取用户名
        SysUser sysUser=(SysUser) request.getSession().getAttribute("user");
        sysLog.setUsername(sysUser.getUsername());
        //获取用户ip地址
        sysLog.setIp(IpUtiles.getRealIp(request));
        //请求的参数
        Object[] args = joinPoint.getArgs();
        //将参数所在的数组转换成json
        String params = JSON.toJSONString(args);
        sysLog.setParams(params);
        //调用service保存SysLog实体类到数据库
        sysLogService.saveSysLog(sysLog);
    }

}

获取ip工具类

如果用户经过多层代理,工具类依然不能获取用户真正ip

代码语言:javascript
复制
import javax.servlet.http.HttpServletRequest;

/**
 * @ProjectName: 
 * @Package: 
 * @Author: huat
 * @Date: 2020/3/5 22:50
 * @Version: 1.0
 */
public class IpUtiles {
    /**
     * 获取真实IP
     * @param request 请求体
     * @return 真实IP
     */
    public static String getRealIp(HttpServletRequest request) {
        // 这个一般是Nginx反向代理设置的参数
        String ip = request.getHeader("X-Real-IP");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Forwarded-For");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        // 处理多IP的情况(只取第一个IP)
        if (ip != null && ip.contains(",")) {
            String[] ipArray = ip.split(",");
            ip = ipArray[0];
        }
        return ip;
    }
}

自定义注解

切面仅在子定义注解的方法上生效,自定义注解为接口名称,这里我的注解为@MyLog

代码语言:javascript
复制
@Target(ElementType.METHOD) //注解放置的目标位置,METHOD是可注解在方法级别上
@Retention(RetentionPolicy.RUNTIME) //注解在哪个阶段执行
@Documented //生成文档
public @interface MyLog {
    String value() default "";
}

用户退出登陆操作

因为用户退出有可能直接关闭浏览器等非正常操作,所以这里直接用session监听器去监听

代码语言:javascript
复制
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import java.util.Date;

/**
 * @ProjectName: 
 * @Package: 
 * @Author: huat
 * @Date: 2020/3/6 13:49
 * @Version: 1.0
 */
@Component
public class MyHttpSessionListener implements HttpSessionListener {
    @Autowired
    SysLogService sysLogService;
    @Override
    public void sessionCreated(HttpSessionEvent httpSessionEvent) {

    }

    @Override
    public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
        SysUser sysUser=(SysUser) httpSessionEvent.getSession().getAttribute("user");
        SysLog sysLog=new SysLog();
        sysLog.setUsername(sysUser.getUsername());
        sysLog.setMethod("loginout");
        sysLog.setCreateDate(new Date());
        sysLog.setIp(null);
        sysLog.setOperation("退出系统");
        sysLog.setParams(null);
        sysLogService.saveSysLog(sysLog);
    }
}

登陆

因为登陆操作使用的是security的方法,所以在登陆后直接跳转一个我们自定义的方法,在此方法中记录用户操作然后在进入首页

代码语言:javascript
复制
 @RequestMapping("jumpIndex")
    public String jumpIndex(HttpSession session) {

            //记录用户登陆操作
            SysLog sysLog=new SysLog();
            sysLog.setUsername(SecurityContextHolder.getContext().getAuthentication().getName());
            sysLog.setCreateDate(new Date());
            HttpServletRequest request=((ServletRequestAttributes) RequestContextHolder
                    .getRequestAttributes()).getRequest();
            sysLog.setIp(IpUtiles.getRealIp(request));
            sysLog.setOperation("登陆成功");
            sysLog.setMethod("login");
            sysLogService.saveSysLog(sysLog);
            return "redirect:"+request.getContextPath()+"sys/user/index";
   }
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 数据库
  • 实体类
  • 切面
  • 获取ip工具类
  • 自定义注解
  • 用户退出登陆操作
  • 登陆
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档