springboot+security 记录用户操作日志

数据库



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');

实体类

@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; //操作时间

切面

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


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



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

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

用户退出登陆操作

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


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的方法,所以在登陆后直接跳转一个我们自定义的方法,在此方法中记录用户操作然后在进入首页

 @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";
   }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
当我们使用SpringBoot + Spring Security + MyBatis进行Web应用程序的开发时,通常会涉及以下几个方面的功能: 1. 用户认证和授权:Spring Security是一个强大的安全框架,可以帮助我们实现用户认证和授权功能。它提供了多种认证方式,支持基于用户名和密码、LDAP、OAuth等方式进行认证。同时,它也提供了多种授权策略,可以根据用户角色、权限等信息进行授权。在Spring Security中,我们通常需要实现UserDetailsService接口来加载用户信息,同时也需要实现AccessDecisionManager接口来控制访问权限。 2. 数据库访问:MyBatis是一个流行的ORM框架,可以帮助我们实现数据库访问功能。它提供了多种方式来执行SQL语句,包括注解、XML文件、动态SQL等方式。同时,它也提供了多种映射方式,可以将数据库表映射为Java对象,从而实现对象关系映射。在Spring Boot中,我们通常需要使用MyBatis-Spring-Boot-Starter来启用MyBatis的自动配置功能。 3. RESTful接口开发:Spring Boot提供了一套强大的RESTful框架,可以帮助我们实现Web API的开发。它提供了多种注解来定义API的请求路径、请求方法、请求参数等信息,同时也提供了多种返回类型,包括JSON、XML、HTML等。在Spring Boot中,我们通常需要使用@RestController注解来定义RestController,同时也需要使用@RequestMapping注解来定义API的请求路径和请求方法。 4. 日志记录Spring Boot提供了一套强大的日志框架,可以帮助我们记录应用程序的运行日志。它提供了多种日志级别,可以根据需要进行配置,同时也提供了多种输出方式,包括控制台输出、文件输出等。在Spring Boot中,我们通常需要使用logback或log4j2来实现日志记录功能。 总之,当我们使用Spring Boot + Spring Security + MyBatis进行Web应用程序的开发时,需要掌握以上几个方面的功能,并将它们有机地结合起来,从而实现高效、安全、可维护的应用程序。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

半夜燃烧的香烟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值