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.jykj.materiel.util;

import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;

/**
 * @Author: hjl
 * @Date: 2020/11/13 0013 9:57
 */
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();
        }
        String comma = ",";
        String localhost = "127.0.0.1";
        if (ip.contains(comma)) {
            ip = ip.split(",")[0];
        }
        if  (localhost.equals(ip))  {
            // 获取本机真正的ip地址
            try {
                ip = InetAddress.getLocalHost().getHostAddress();
            } catch (UnknownHostException e) {
                e.printStackTrace();
            }
        }
        return ip;
    }
}

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记录日志

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Spring Security 是一个基于 Spring 的安全框架,提供了一组完整的安全性功能,包括身份验证、授权、防止 CSRF 攻击等等。Spring Boot 基于 Spring,自然也集成Spring Security。下面是 Spring Boot 集成 Spring Security 的步骤: 1. 在 pom.xml 中添加 Spring Security 的依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> ``` 2. 编写一个继承自 WebSecurityConfigurerAdapter 的配置类,并使用 @EnableWebSecurity 注解开启 Spring Security: ```java @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/", "/home").permitAll() .anyRequest().authenticated() .and() .formLogin() .loginPage("/login") .permitAll() .and() .logout() .permitAll(); } @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth .inMemoryAuthentication() .withUser("user").password("password").roles("USER"); } } ``` 上面的代码中,我们配置了 Spring Security 的基本功能:对所有请求进行身份验证,允许访问首页和登录页面,使用 inMemoryAuthentication 来指定用户和密码。 3. 在 application.properties 或 application.yml 中配置登录页面的 URL: ```properties spring.security.login.form=/login ``` 4. 编写一个登录页面,例如一个 Thymeleaf 模板: ```html <!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Login</title> </head> <body> <form th:action="@{/login}" method="post"> <div><label>Username: <input type="text" name="username"/></label></div> <div><label>Password: <input type="password" name="password"/></label></div> <div><input type="submit" value="Log in"/></div> </form> </body> </html> ``` 这样就完成了 Spring Boot 集成 Spring Security 的配置。当用户访问受保护的页面时,会被重定向到登录页面进行身份验证。如果用户输入的用户名和密码正确,就会跳转到原来请求的页面。如果不正确,就会显示错误信息。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值