springboot+security 记录用户操作日志

springboot+security 记录用户操作日志


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