SpringBoot集成Spring Security(一)——添加用户操作日志

SpringBoot集成Spring Security(1)——入门程序中添加日志功能。
原理:利用Spring Aop面向切面来获取信息。
步骤如下:

在原github上修改项目

1.添加依赖

		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

2.工具类

IpUtiles.java

package com.hjl.springsecurity.util;


import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.util.*;

/**
 * @Author: hjl
 * @Date: 2020/11/13 0013 10:29
 */
public class JsonUtiles {
    
    
    private static final ObjectMapper MAPPER = new ObjectMapper();

    /**
     * 将对象转换成json字符串。
     * <p>Title: pojoToJson</p>
     * <p>Description: </p>
     * @param data
     * @return
     */
    public static String objectToJson(Object data) {
    
    
        try {
    
    
            String string = MAPPER.writeValueAsString(data);
            return string;
        } catch (JsonProcessingException e) {
    
    
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 将json结果集转化为对象
     *
     * @param jsonData json数据
     * @param beanType 对象中的object类型
     * @return
     */
    public static <T> T jsonToPojo(String jsonData, Class<T> beanType) {
    
    
        try {
    
    
            T t = MAPPER.readValue(jsonData, beanType);
            return t;
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 将json数据转换成pojo对象list
     * <p>Title: jsonToList</p>
     * <p>Description: </p>
     * @param jsonData
     * @param beanType
     * @return
     */
    public static <T> List<T> jsonToList(String jsonData, Class<T> beanType) {
    
    
        JavaType javaType = MAPPER.getTypeFactory().constructParametricType(List.class, beanType);
        try {
    
    
            List<T> list = MAPPER.readValue(jsonData, javaType);
            return list;
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }

        return null;
    }


}

JsonUtiles.java

package com.hjl.springsecurity.util;


import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.util.*;

/**
 * @Author: hjl
 * @Date: 2020/11/13 0013 10:29
 */
public class JsonUtiles {
    
    
    private static final ObjectMapper MAPPER = new ObjectMapper();

    /**
     * 将对象转换成json字符串。
     * <p>Title: pojoToJson</p>
     * <p>Description: </p>
     * @param data
     * @return
     */
    public static String objectToJson(Object data) {
    
    
        try {
    
    
            String string = MAPPER.writeValueAsString(data);
            return string;
        } catch (JsonProcessingException e) {
    
    
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 将json结果集转化为对象
     *
     * @param jsonData json数据
     * @param beanType 对象中的object类型
     * @return
     */
    public static <T> T jsonToPojo(String jsonData, Class<T> beanType) {
    
    
        try {
    
    
            T t = MAPPER.readValue(jsonData, beanType);
            return t;
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 将json数据转换成pojo对象list
     * <p>Title: jsonToList</p>
     * <p>Description: </p>
     * @param jsonData
     * @param beanType
     * @return
     */
    public static <T> List<T> jsonToList(String jsonData, Class<T> beanType) {
    
    
        JavaType javaType = MAPPER.getTypeFactory().constructParametricType(List.class, beanType);
        try {
    
    
            List<T> list = MAPPER.readValue(jsonData, javaType);
            return list;
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }

        return null;
    }
}

3.新建日志实体类和基本的业务

SysLog.java实体类

package com.hjl.springsecurity.entity;

import java.io.Serializable;
/**
 * @Author: hjl
 * @Date: 2020/11/13 0013 9:54
 */
public class SysLog implements Serializable {
    
    
    private Long id;

    private String uri;//请求接口

    private String method;//请求方式

    private String MethodDescribe;//描述

    private String params;//参数

    private String username; //用户名

    private String ip; //ip地址

    private String createDate; //操作时间

    private String browser;//浏览器类型

    public Long getId() {
    
    
        return id;
    }

    public void setId(Long id) {
    
    
        this.id = id;
    }

    public String getUri() {
    
    
        return uri;
    }

    public void setUri(String uri) {
    
    
        this.uri = uri;
    }

    public String getMethod() {
    
    
        return method;
    }

    public void setMethod(String method) {
    
    
        this.method = method;
    }

    public String getMethodDescribe() {
    
    
        return MethodDescribe;
    }

    public void setMethodDescribe(String methodDescribe) {
    
    
        MethodDescribe = methodDescribe;
    }

    public String getParams() {
    
    
        return params;
    }

    public void setParams(String params) {
    
    
        this.params = params;
    }

    public String getUsername() {
    
    
        return username;
    }

    public void setUsername(String username) {
    
    
        this.username = username;
    }

    public String getIp() {
    
    
        return ip;
    }

    public void setIp(String ip) {
    
    
        this.ip = ip;
    }

    public String getCreateDate() {
    
    
        return createDate;
    }

    public void setCreateDate(String createDate) {
    
    
        this.createDate = createDate;
    }

    public String getBrowser() {
    
    
        return browser;
    }

    public void setBrowser(String browser) {
    
    
        this.browser = browser;
    }
}

SysLogService接口

package com.hjl.springsecurity.service;

import com.hjl.springsecurity.entity.SysLog;

/**
 * @Author: hjl
 * @Date: 2020/11/13 0013 15:33
 */
public interface SysLogService {
    
    
    //添加用户操作日志
    void InsertSysLog(SysLog sysLog);
}

SysLogServiceImpl.java

package com.hjl.springsecurity.service.impl;

import com.hjl.springsecurity.dao.SysLogMapper;
import com.hjl.springsecurity.entity.SysLog;
import com.hjl.springsecurity.service.SysLogService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @Author: hjl
 * @Date: 2020/11/13 0013 15:34
 */
@Service
public class SysLogServiceImpl implements SysLogService {
    
    
    @Autowired
    private SysLogMapper  sysLogMapper;

    @Override
    public void InsertSysLog(SysLog sysLog) {
    
    
        sysLogMapper.InsertSysLog(sysLog);
    }


}

SysLogMapper接口

package com.hjl.springsecurity.dao;

import com.hjl.springsecurity.entity.SysLog;
import org.apache.ibatis.annotations.Mapper;

/**
 * @Author: hjl
 * @Date: 2020/11/13 0013 15:44
 */
@Mapper
public interface SysLogMapper {
    
    
       void InsertSysLog(SysLog sysLog);
}

SysLogMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hjl.springsecurity.dao.SysLogMapper">
   
<insert id="InsertSysLog"  parameterType="com.hjl.springsecurity.entity.SysLog">
       INSERT INTO sys_log(uri,method,MethodDescribe,params,username,ip,create_date,browser) VALUES(#{uri},#{method},#{MethodDescribe},#{params},#{username},#{ip},#{createDate},#{browser});
</insert>
</mapper>

application.yml配置

server:
  port: 8080

spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/security?serverTimezone=Asia/Shanghai&allowMultiQueries=true&characterEncoding=utf-8
    password: root
    username: root
  devtools:
    restart:
      additional-paths: src/main/java
      enabled: true
  thymeleaf:
    cache: true
  #切面启用
  aop:
    proxy-target-class: true
    auto: true

logging:
  level:
    com:
      hjl:
        springsecurity:
          dao: debug
mybatis:
  configuration:
    map-underscore-to-camel-case: true
  mapper-locations: classpath:/mapper/*.xml

4.自定义操作日志的注解类SystemLogService和SystemLogController

aop主要是以下代码

package com.hjl.springsecurity.config;

import java.lang.annotation.*;

/**
 * @Author: hjl
 * @Date: 2020/11/13 0013 10:22
 */
@Target({
    
    ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SystemLogService {
    
    
    String description() default "";
}
package com.hjl.springsecurity.controller;

import java.lang.annotation.*;

/**
 * @Author: hjl
 * @Date: 2020/11/13 0013 10:20
 */
@Target({
    
    ElementType.PARAMETER, ElementType.METHOD})//作用在参数和方法上
@Retention(RetentionPolicy.RUNTIME)//运行时注解
@Documented//表明这个注解应该被 javadoc工具记录
public @interface SystemLogController {
    
    
    String description() default "";
}

5.切面类SystemLogAspect.java

package com.hjl.springsecurity.config;

import com.hjl.springsecurity.controller.SystemLogController;
import com.hjl.springsecurity.entity.SysLog;
import com.hjl.springsecurity.entity.SysUser;
import com.hjl.springsecurity.service.SysLogService;
import com.hjl.springsecurity.util.IpUtiles;
import com.hjl.springsecurity.util.JsonUtiles;
import nl.bitwalker.useragentutils.Browser;
import nl.bitwalker.useragentutils.UserAgent;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
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 javax.servlet.http.HttpSession;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

/**
 * @Author: hjl
 * @Date: 2020/11/13 0013 10:22
 */
@Aspect
@Component
@SuppressWarnings("all")
public class SystemLogAspect {
    
    

    @Autowired
    private SysLogService sysLogService;

    //本地异常日志记录对象
    private static final Logger logger = LoggerFactory.getLogger(SystemLogAspect.class);
    //Service层切点
    @Pointcut("@annotation(com.hjl.springsecurity.config.SystemLogService)")
    public void serviceAspect(){
    
    
    }

    //Controller层切点
    @Pointcut("@annotation(com.hjl.springsecurity.controller.SystemLogController)")
    public void controllerAspect(){
    
    
    }

    /**
     * @Description  前置通知  用于拦截Controller层记录用户的操作
     * @date 2018年9月3日 10:38
     */
    @Before("controllerAspect()")
    public void doBefore(JoinPoint joinPoint){
    
    
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        //读取用户
        String  name = SecurityContextHolder.getContext().getAuthentication().getName();
        //获取ip
        String ip = IpUtiles.getRealIp(request);
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
        try {
    
    
            //*========控制台输出=========*//
            System.out.println("==============前置通知开始==============");
            System.out.println("请求接口 uri:"+request.getRequestURI().toString()); //接口
//            logger.info("URL : " + request.getRequestURL().toString()); //完整地址
            System.out.println("请求方式 method:"+request.getMethod());
//            System.out.println("请求方法:" + joinPoint.getSignature().toString());
            System.out.println("方法描述 method_describe:" + getControllerMethodDescription(joinPoint));
            System.out.println("参数信息 params:" + Arrays.toString(joinPoint.getArgs()));
            System.out.println("请求人 username:"+name);
            System.out.println("请求 ip:"+ip);
            System.out.println("请求时间 create_date:"+df.format(new Date()));
            String ua = request.getHeader("User-Agent");
            //转成UserAgent对象
            UserAgent userAgent = UserAgent.parseUserAgentString(ua);
            //获取浏览器信息
            Browser browser = userAgent.getBrowser();
            String browserName = browser.getName();
            System.out.println("浏览器 browser:"+browserName);

            //*========数据库日志=========*//
            SysLog sysLog=new SysLog();
            sysLog.setUri(request.getRequestURI().toString());//请求接口
            sysLog.setMethod(request.getMethod());//请求方式
            sysLog.setMethodDescribe(getControllerMethodDescription(joinPoint));//描述
            sysLog.setParams(Arrays.toString(joinPoint.getArgs()));//参数信息
            sysLog.setUsername(name);//请求人
            sysLog.setIp(ip);//ip
            sysLog.setCreateDate(df.format(new Date()));//请求时间
            sysLog.setBrowser(browserName);//浏览器类型
            sysLogService.InsertSysLog(sysLog);

        }catch (Exception e){
    
    
            //记录本地异常日志
            logger.error("==前置通知异常==");
            logger.error("异常信息:{}",e.getMessage());
        }
    }


    @AfterReturning(returning = "ret", pointcut = "controllerAspect()")
    public void doAfterReturning(Object ret) throws Throwable {
    
    
        // 处理完请求,返回内容
        logger.info("RESPONSE : " + ret);
    }



    /**
     * @Description  异常通知 用于拦截service层记录异常日志
     * @date 2018年9月3日 下午5:43
     */
    @AfterThrowing(pointcut = "serviceAspect()",throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint,Throwable e){
    
    
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        HttpSession session = request.getSession();
        //读取session中的用户
        SysUser user = (SysUser) session.getAttribute("user");
        //获取请求ip
        String ip = IpUtiles.getRealIp(request);
        //获取用户请求方法的参数并序列化为JSON格式字符串
        String params = "";
        if (joinPoint.getArgs()!=null&&joinPoint.getArgs().length>0){
    
    
            for (int i = 0; i < joinPoint.getArgs().length; i++) {
    
    
                params+= JsonUtiles.objectToJson(joinPoint.getArgs()[i])+";";
            }
        }
        try{
    
    
            /*========控制台输出=========*/
            System.out.println("=====异常通知开始=====");
            System.out.println("异常代码:" + e.getClass().getName());
            System.out.println("异常信息:" + e.getMessage());
            System.out.println("异常方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));
            System.out.println("方法描述:" + getServiceMethodDescription(joinPoint));
            System.out.println("请求人:" + user.getName());
            System.out.println("请求IP:" + ip);
            System.out.println("请求参数:" + params);
            /*==========数据库日志=========*/

        }catch (Exception ex){
    
    
            //记录本地异常日志
            logger.error("==异常通知异常==");
            logger.error("异常信息:{}", ex.getMessage());
        }
    }


    /**
     * @Description  获取注解中对方法的描述信息 用于service层注解
     * @date 2018年9月3日 下午5:05
     */
    public static String getServiceMethodDescription(JoinPoint joinPoint)throws Exception{
    
    
        String targetName = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        Object[] arguments = joinPoint.getArgs();
        Class targetClass = Class.forName(targetName);
        Method[] methods = targetClass.getMethods();
        String description = "";
        for (Method method:methods) {
    
    
            if (method.getName().equals(methodName)){
    
    
                Class[] clazzs = method.getParameterTypes();
                if (clazzs.length==arguments.length){
    
    
                    description = method.getAnnotation(SystemLogService.class).description();
                    break;
                }
            }
        }
        return description;
    }



    /**
     * @Description  获取注解中对方法的描述信息 用于Controller层注解
     * @date 2018年9月3日 上午12:01
     */
    public static String getControllerMethodDescription(JoinPoint joinPoint) throws Exception {
    
    
        String targetName = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();//目标方法名
        Object[] arguments = joinPoint.getArgs();
        Class targetClass = Class.forName(targetName);
        Method[] methods = targetClass.getMethods();
        String description = "";
        for (Method method:methods) {
    
    
            if (method.getName().equals(methodName)){
    
    
                Class[] clazzs = method.getParameterTypes();
                if (clazzs.length==arguments.length){
    
    
                    description = method.getAnnotation(SystemLogController.class).description();
                    break;
                }
            }
        }
        return description;
    }
}

使用注解记录日志

 	@RequestMapping("/")
    @SystemLogController(description = "主页") //添加
    public String showHome(){
    
    
        String name= SecurityContextHolder.getContext().getAuthentication().getName();
        logger.info("当前登录用户:{}",name);
        return "home.html";
    }

效果:
在这里插入图片描述
—End
master2分支
github:SpringSecurity+Aop记录日志

猜你喜欢

转载自blog.csdn.net/qq_40286424/article/details/109679152