一、登录日志

  1. 编写登录日志记录接口
package com.xxz.system.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.xxz.model.system.SysLoginLog;
import org.apache.ibatis.annotations.Mapper;/*** 登录日志记录Mapper接口*/
@Mapper
public interface LoginLogMapper extends BaseMapper<SysLoginLog> {
}
package com.xxz.system;/*** 记录登录日志接口*/
public interface LoginLogService {//编写记录登录日志方法public void recordLoginLog(String username, Integer status, String ipaddr, String message);}
  1. 编写登录日志记录接口实现类
 package com.xxz.system.service;import com.xxz.model.system.SysLoginLog;
import com.xxz.system.LoginLogService;
import com.xxz.system.mapper.LoginLogMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;/*** 记录登录日志实现类*/
@Service
public class LoginLogServiceImpl implements LoginLogService {@Autowiredprivate LoginLogMapper loginLogMapper;//目标方法@Overridepublic void recordLoginLog(String username, Integer status, String ipaddr, String message) {SysLoginLog sysLoginLog = new SysLoginLog();sysLoginLog.setUsername(username);sysLoginLog.setStatus(status);sysLoginLog.setIpaddr(ipaddr);sysLoginLog.setMsg(message);loginLogMapper.insert(sysLoginLog);}
}
  1. Security核心配置
package com.xxz.system.config;import com.xxz.system.LoginLogService;
import com.xxz.system.custom.CustomMD5Password;
import com.xxz.system.filter.TokenAuthenticationFilter;
import com.xxz.system.filter.TokenLoginFilter;
import com.xxz.system.service.UserDetailServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;/*** 六、配置SpirngSecurity配置类(自定义大整合)*/
@Configuration
@EnableWebSecurity //开启SpringSecurity的默认行为
@Slf4j //日志
@EnableGlobalMethodSecurity(prePostEnabled = true) //开启注解功能,默认禁用注解
public class MySecurityConfig extends WebSecurityConfigurerAdapter {//导入自己编写的查询业务类(默认是providerService去内存查找)@Autowiredprivate UserDetailServiceImpl userDetailsService;//导入我们自己编写的加密工具类@Autowiredprivate CustomMD5Password customMD5Password;//[new 权限]:注入redistemplate依赖@Autowiredprivate RedisTemplate redisTemplate;//[new 记录登录信息]@Autowiredprivate LoginLogService loginLogService;/**  用户认证管理器* @return* @throws Exception*/@Bean@Overrideprotected AuthenticationManager authenticationManager()throws Exception{log.info("AuthenticationManager用户认证管理器 + 加入容器.......");log.info("当前注入对象UserDetailsService : ===== " + userDetailsService);return super.authenticationManager();}@Overrideprotected void configure(HttpSecurity http)throws Exception{//这是配置的关键,决定那些接口开启防护,那些接口绕过防护http//关闭csrf.csrf().disable()//开启跨域以便前端调用接口.cors().and().authorizeRequests()//指定某些接口不需要通过认证即可访问, 登录接口肯定是不需要的.antMatchers("/admin/system/index/login").permitAll()//这里的意思是其他所有接口需要认证才能访问.anyRequest().authenticated().and()//TokenAuthenticationFilter放到UsernamePasswordAuthenticationFilter的前面 [new 权限:注入redistemplate].addFilterBefore(new TokenAuthenticationFilter(redisTemplate), UsernamePasswordAuthenticationFilter.class).addFilter(new TokenLoginFilter(authenticationManager(), redisTemplate, loginLogService));//禁用sessionhttp.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);}@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception{//指定UserDetailService和加密器(使用自定义的)log.info("指定UserDetailService和加密器(使用自定义的) + 加入容器.......");auth.userDetailsService(userDetailsService).passwordEncoder(customMD5Password);}/*** 配置那些请求不拦截* 排除swagger 相关请求* @param web* @throws Exception*/@Overridepublic void configure(WebSecurity web)throws Exception{web.ignoring().antMatchers("/favicon.ico","/swagger-resources/**","/webjars/**", "/v2/**","/swagger-ui.html","/doc.html");}}
  1. 实现记录业务
package com.xxz.system.filter;import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xxz.common.result.Result;
import com.xxz.common.result.ResultCodeEnum;
import com.xxz.common.utils.IpUtil;
import com.xxz.common.utils.JwtHelper;
import com.xxz.common.utils.ResponseUtil;
import com.xxz.model.vo.LoginVo;
import com.xxz.system.LoginLogService;
import com.xxz.system.custom.CustomUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;/*** 登入过滤器,继承UserNamePasswordAuthenticationFilter , 对用户名密码进行登录校验*///四、自定义认证过滤器 //继承               UsernamePasswordAuthenticationFilter
public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter {//[new 授权]private RedisTemplate redisTemplate;//登录日志业务[new 登录日志记录]private LoginLogService loginLogService;//定义构造器用于做当前登录过滤器初始化 [new 授权]public TokenLoginFilter(AuthenticationManager authenticationManager, RedisTemplate redisTemplate, LoginLogService loginLogService){//设置/初始化  认证管理器this.setAuthenticationManager(authenticationManager);//取消 只针对post请求this.setPostOnly(false);//指定登录接口及提交方式,可以指定任意路径this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/admin/system/index/login", "POST"));//[new 授权]this.redisTemplate = redisTemplate;}//重写获取用户信息方法@Overridepublic Authentication attemptAuthentication(HttpServletRequest request,HttpServletResponse response) throws AuthenticationException {try {//以流的方式获取前端请求接口封装的用户对象LoginVo loginVo = new ObjectMapper().readValue(request.getInputStream(), LoginVo.class);//创建UsernamePasswordAuthenticationToken对象,封装用户名和密码,得到认证对象Authentication authenticationToken =new UsernamePasswordAuthenticationToken(loginVo.getUsername(), loginVo.getPassword());//返回目标认证对象Authentication authentication = this.getAuthenticationManager().authenticate(authenticationToken);System.out.println("authenticate ===== " + authentication);return authentication;}catch (IOException e){e.printStackTrace();}return null;}//重写登录成功调用/执行@Overrideprotected void successfulAuthentication(HttpServletRequest request,HttpServletResponse response,FilterChain chain,Authentication auth) throws IOException, ServletException {//auth : 表示当前认证对象//1.获取认证对象CustomUser customUser = (CustomUser) auth.getPrincipal();System.out.println("===========================================================");System.out.println("===========================================================");System.out.println("===========================================================");System.out.println(" auth.getDetails(); : ==== " +  auth);System.out.println("===========================================================");System.out.println("===========================================================");System.out.println("===========================================================");//[new 授权]:认证成功后,将用户数据存储到redis中 (以用户名称作为key,以Json作为存储数据)redisTemplate.opsForValue().set(customUser.getUsername(),JSON.toJSONString(customUser.getAuthorities()));//[new 登录日志记录]loginLogService.recordLoginLog(customUser.getUsername(), 1, IpUtil.getIpAddress(request), "登录成功...");//2.生成tokenString token = JwtHelper.createToken(customUser.getSysUser().getId(), customUser.getSysUser().getUsername());//3.返回(通过响应工具)Map<String, Object> map = new HashMap<>();map.put("token", token);ResponseUtil.out(response, Result.ok(map));}//重写登录失败调用/执行@Overrideprotected void unsuccessfulAuthentication(HttpServletRequest request,HttpServletResponse response,AuthenticationException e) throws IOException, ServletException {//判断当前异常是否属于运行时异常if(e.getCause() instanceof RuntimeException){ResponseUtil.out(response, Result.build(null, 204, e.getMessage()));}else{ResponseUtil.out(response, Result.build(null, ResultCodeEnum.LOGIN_MOBLE_ERROR));}}}

二、操作日志

  1. 导入依赖
    <!--导入aop依赖--><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency></dependencies>
  1. 自定义注解
package com.xxz.log.enums;/*** 业务操作类别*/
public enum BusinessType {/*** 其他*/OTHER,/*** 新增*/INSERT,/*** 修改*/UPDATE,/*** 删除*/DELETE,/*** 强退*/FORCE,/*** 更新状态*/STATUS,/*** 清空数据*/CLEAN}
package com.xxz.log.enums;/*** 操作人类别*/
public enum OperatorType {/*** 其他*/OTHER,/*** 后台用户*/MANAGE,/*** 手机端*/MOBILE}
package com.xxz.log.annotation;import com.xxz.log.enums.BusinessType;
import com.xxz.log.enums.OperatorType;import java.lang.annotation.*;@Target({ElementType.PARAMETER, ElementType.METHOD}) //参数、方法上
@Retention(RetentionPolicy.RUNTIME) //作用范围:运行时
@Documented
public @interface Log {/*** 模块*/public String title() default "";/*** 功能*/public BusinessType businessType() default BusinessType.OTHER;/*** 操作人类别*/public OperatorType operatorType() default OperatorType.MANAGE;/*** 是否保存请求参数*/public boolean isSaveRequestData() default true;/*** 是否保存响应的参数*/public boolean isSaveResponseData() default true;}
  1. 自定义切面
package com.xxz.log.aspect;import com.alibaba.fastjson.JSON;
import com.xxz.common.utils.IpUtil;
import com.xxz.common.utils.JwtHelper;
import com.xxz.log.annotation.Log;
import com.xxz.log.service.OperLogService;
import com.xxz.model.system.SysOperLog;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindingResult;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Collection;
import java.util.Map;@Aspect
@Component
public class LogAspect {@Autowiredprivate OperLogService operLogService;@AfterReturning(pointcut = "@annotation(controllerLog)", returning = "jsonResult")public void doAfterReturning(JoinPoint joinPoint, Log controllerLog, Object jsonResult) {handleLog(joinPoint, controllerLog, null, jsonResult);}protected void handleLog(final JoinPoint joinPoint, Log controllerLog, final Exception e, Object jsonResult) {try {RequestAttributes ra = RequestContextHolder.getRequestAttributes();ServletRequestAttributes sra = (ServletRequestAttributes) ra;HttpServletRequest request = sra.getRequest();// *========数据库日志=========*//SysOperLog operLog = new SysOperLog();//状态operLog.setStatus(1);// 请求的地址String ip = IpUtil.getIpAddress(request);//IpUtil.getIpAddr(ServletUtils.getRequest());operLog.setOperIp(ip);operLog.setOperUrl(request.getRequestURI());String token = request.getHeader("token");String userName = JwtHelper.getUsername(token);operLog.setOperName(userName);if (e != null) {operLog.setStatus(0);operLog.setErrorMsg(e.getMessage());}// 设置方法名称String className = joinPoint.getTarget().getClass().getName();String methodName = joinPoint.getSignature().getName();operLog.setMethod(className + "." + methodName + "()");// 设置请求方式operLog.setRequestMethod(request.getMethod());// 处理设置注解上的参数getControllerMethodDescription(joinPoint, controllerLog, operLog, jsonResult);// 操作日志保存数据库operLogService.saveSysLog(operLog);} catch (Exception exp) {exp.printStackTrace();}}/*** 获取注解中对方法的描述信息 用于Controller层注解** @param log     日志* @param operLog 操作日志* @throws Exception*/public void getControllerMethodDescription(JoinPoint joinPoint, Log log, SysOperLog operLog, Object jsonResult) throws Exception {// 设置action动作operLog.setBusinessType(log.businessType().name());// 设置标题operLog.setTitle(log.title());// 设置操作人类别operLog.setOperatorType(log.operatorType().name());// 是否需要保存request,参数和值if (log.isSaveRequestData()) {// 获取参数的信息,传入到数据库中。setRequestValue(joinPoint, operLog);}// 是否需要保存response,参数和值if (log.isSaveResponseData() && !StringUtils.isEmpty(jsonResult)) {operLog.setJsonResult(JSON.toJSONString(jsonResult));}}/*** 获取请求的参数,放到log中** @param operLog 操作日志* @throws Exception 异常*/private void setRequestValue(JoinPoint joinPoint, SysOperLog operLog) throws Exception {String requestMethod = operLog.getRequestMethod();if (HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod)) {String params = argsArrayToString(joinPoint.getArgs());operLog.setOperParam(params);}}/*** 参数拼装*/private String argsArrayToString(Object[] paramsArray) {String params = "";if (paramsArray != null && paramsArray.length > 0) {for (Object o : paramsArray) {if (!StringUtils.isEmpty(o) && !isFilterObject(o)) {try {Object jsonObj = JSON.toJSON(o);params += jsonObj.toString() + " ";} catch (Exception e) {}}}}return params.trim();}/*** 判断是否需要过滤的对象。** @param o 对象信息。* @return 如果是需要过滤的对象,则返回true;否则返回false。*/@SuppressWarnings("rawtypes")public boolean isFilterObject(final Object o) {Class<?> clazz = o.getClass();if (clazz.isArray()) {return clazz.getComponentType().isAssignableFrom(MultipartFile.class);} else if (Collection.class.isAssignableFrom(clazz)) {Collection collection = (Collection) o;for (Object value : collection) {return value instanceof MultipartFile;}} else if (Map.class.isAssignableFrom(clazz)) {Map map = (Map) o;for (Object value : map.entrySet()) {Map.Entry entry = (Map.Entry) value;return entry.getValue() instanceof MultipartFile;}}return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse|| o instanceof BindingResult;}
}
  1. mapper、service、实现类 、controller雷同
package com.xxz.log.service;import com.baomidou.mybatisplus.core.metadata.IPage;
import com.xxz.model.system.SysOperLog;
import com.xxz.model.vo.SysOperLogQueryVo;public interface OperLogService {public void saveSysLog(SysOperLog sysOperLog);//操作日志分页查询IPage<SysOperLog> selectPage(Long page, Long limit, SysOperLogQueryVo sysOperLogQueryVo);
}
  1. 使用方式

登录日志/操作日志AOP记录实现(续SpringSecurity)相关推荐

  1. 在Linux下记录所有用户的登录和操作日志

    一般我们可以用history命令来查看用户的操作记录,但是这个命令不能记录是哪个用户登录操作的,也不能记录详细的操作时间,且不完整:所以误操作而造成重要的数据丢失,就很难查到是谁操作的.   在这里我 ...

  2. linux 查看用户操作日志,Linux下记录所有用户的登录和操作日志

    一般我们可以用history命令来查看用户的操作记录,但是这个命令不能记录是哪个用户登录操作的,也不能记录详细的操作时间,且不完整:所以误操作而造成重要的数据丢失,就很难查到是谁操作的. 在这里我们通 ...

  3. linux查看登录服务器的ip历史记录,通过登陆IP记录Linux所有用户登录所操作日志的方法...

    对于Linux用户操作记录一般通过命令history来查看历史记录,但是如果在由于误操作而删除了重要的数据的情况下,history命令就不会有什么作用了.那么依然要存有历史操作记录应该如何来实现呢? ...

  4. linux有不知名ip登录记录,通过登陆IP记录Linux所有用户登录所操作日志的方法

    对于Linux用户操作记录一般通过命令history来查看历史记录,但是如果在由于误操作而删除了重要的数据的情况下,history命令就不会有什么作用了.那么依然要存有历史操作记录应该如何来实现呢? ...

  5. 华为交换机本地查看登录和操作日志

    目录 1.问题 2.解决 3.查看方法 4.为什么华为S系列交换机logbuffer 不展示用户登录和操作命令日志? 4.如何配置将登录日志和操作日志输出到logbuffer 1.问题 华为S系列交换 ...

  6. SpringBoot AOP 记录操作日志、异常日志

    使用SpringBoot AOP 记录操作日志.异常日志 我们在做项目时经常需要对一些重要功能操作记录日志,方便以后跟踪是谁在操作此功能.在操作某些功能时也有可能会发生异常,但是每次发生异常要定位原因 ...

  7. openresty ngx_lua日志操作

    openresty ngx_lua日志操作 日志操作 ngx.log:向日志文件输出日志 语法格式:ngx.log(log_level, ...)环境:init_by_lua*, init_worke ...

  8. C++ 使用Poco库实现日志操作

    C++ 使用Poco库实现日志操作 flyfish 文章目录 C++ 使用Poco库实现日志操作 日志输出到文件 日志输出到控制台 日志同时输出到文件和控制台 示例:将异常输出到日志 日志输出到文件 ...

  9. Spring AOP 自定义注解记录操作日志

    1.自定义注释 @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Inherited public @interface ...

最新文章

  1. 7的整除特征 三位一截_小学生三位数加法的策略与表现
  2. 磁盘格式化,磁盘挂载,手动增加swap空间
  3. Flask-Login用户登陆
  4. [luogu 2324][SCOI 2005] 骑士精神 (A*算法)
  5. 云计算产值将超3000亿美元 亚马逊微软谷歌居三甲
  6. 求字符串里面数字之和
  7. qt执行命令行失败_QT缺少 qtcore4.dll,debug下运行不成功
  8. MVC.Net:压缩/保存图片缩略图
  9. android mpandroidchart渐变曲线,MPAndroidChart 线条颜色渐变
  10. PostgreSQL视图和物化视图
  11. 金蝶K3 SQL报表系列-委外未勾稽明细表
  12. Python趣用—配平化学方程式
  13. 视频播放器(二)——播放列表
  14. 柱状图中最大的矩形多种解法
  15. Java实现excel大数据量导入
  16. windows10录屏怎么压缩?几个步骤轻松掌握
  17. 如何在一台电脑里面,安装两个操作系统,或者又称为双系统?
  18. 菜鸟弱弱地问:找个薪资待遇差的工作能成长吗?
  19. php 计算一年后的时间,php 计算一年多少周,同时计算出这一周的开始日期和结束日期...
  20. 子曾经曰过,玩笑不能乱开。

热门文章

  1. ENVI拓展插件—焦糖计划:预处理高分系列卫星光学数据(更新至20.03.07)
  2. chatgpt赋能python:Python怎么更换接码平台
  3. 【Keras】 计算机视觉 CNN 实现猫狗图片分类
  4. AtCoder ABC246
  5. iText设置首行缩进
  6. 如何一次性过关软考中、高级
  7. flutter-获取父widget的大小
  8. FastReport.Net教程:基本原理之报表、报表设计器和报表选项
  9. Spring如何整合Mybatis?
  10. 电视剧 片尾曲 王学兵 - 爱是一场等待