新增验证码、登录日志、操作日志记录

This commit is contained in:
tanyp 2023-04-07 14:56:35 +08:00
parent e6c56ebbb1
commit d447ae83be
16 changed files with 404 additions and 83 deletions

View File

@ -11,7 +11,7 @@
Target Server Version : 50721
File Encoding : 65001
Date: 06/04/2023 17:20:01
Date: 07/04/2023 14:54:55
*/
SET NAMES utf8mb4;
@ -64,6 +64,7 @@ CREATE TABLE `sys_login_log` (
-- ----------------------------
-- Records of sys_login_log
-- ----------------------------
INSERT INTO `sys_login_log` VALUES ('165965da5e98b46703683bc655004384', 'admin', '123456', '成功', 'Unknown', 'Unknown', '内网IP', '127.0.0.1', '19aa0675-d451-4232-9221-73babda49078', '2023-04-07 11:33:04');
-- ----------------------------
-- Table structure for sys_menu
@ -107,6 +108,7 @@ DROP TABLE IF EXISTS `sys_oper_log`;
CREATE TABLE `sys_oper_log` (
`id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '主键id',
`module` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '功能模块',
`method` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '操作方法',
`type` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '操作类型',
`message` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '操作描述',
`req_param` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '请求参数',
@ -114,9 +116,10 @@ CREATE TABLE `sys_oper_log` (
`take_up_time` int(64) NULL DEFAULT NULL COMMENT '耗时',
`user_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '操作用户id',
`user_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '操作用户名称',
`method` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '操作方法',
`status` int(1) NULL DEFAULT NULL COMMENT '状态0、成功1、失败',
`uri` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '请求url',
`ip` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '请求IP',
`unusual` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '异常信息',
`version` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '版本号',
`create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE
@ -125,6 +128,7 @@ CREATE TABLE `sys_oper_log` (
-- ----------------------------
-- Records of sys_oper_log
-- ----------------------------
INSERT INTO `sys_oper_log` VALUES ('f052dcb16aeb0fa199bd82aa058e8eee', '菜单管理-当前用户权限菜单列表', 'com.tansci.controller.SysMenuController.menus', 'SELECT', '当前用户权限菜单列表', '{}', '{\"code\":200,\"message\":\"操作成功\",\"result\":[{\"children\":[{\"component\":\"Layout\",\"icon\":\"Grid\",\"id\":\"10001dsgf\",\"isShow\":true,\"meta\":{\"keepAlive\":false,\"openMode\":0,\"id\":\"10001dsgf\",\"title\":\"Iframe测试\",\"isShow\":true},\"name\":\"Iframe\",\"parentId\":\"b1851d1b13594e71840103c11a37a002\",\"path\":\"https://www.bing.com/?mkt=zh-CN\",\"sort\":6},{\"component\":\"Layout\",\"icon\":\"Grid\",\"id\":\"b1851d1b13594e71840103c11a37a003\",\"isShow\":true,\"meta\":{\"keepAlive\":false,\"openMode\":0,\"id\":\"b1851d1b13594e71840103c11a37a003\",\"title\":\"菜单管理\",\"isShow\":true},\"name\":\"menu\",\"parentId\":\"b1851d1b13594e71840103c11a37a002\",\"path\":\"/system/Menu\",\"sort\":2},{\"component\":\"Layout\",\"icon\":\"QuestionFilled\",\"id\":\"b1851d1b13594e71840103c11a37a004\",\"isShow\":true,\"meta\":{\"keepAlive\":false,\"openMode\":0,\"id\":\"b1851d1b13594e71840103c11a37a004\",\"title\":\"组织管理\",\"isShow\":true},\"name\":\"org\",\"parentId\":\"b1851d1b13594e71840103c11a37a002\",\"path\":\"/system/Org\",\"sort\":3},{\"component\":\"Layout\",\"icon\":\"Grid\",\"id\":\"b1851d1b13594e71840103c11a37a005\",\"isShow\":true,\"meta\":{\"keepAlive\":false,\"openMode\":0,\"id\":\"b1851d1b13594e71840103c11a37a005\",\"title\":\"权限管理\",\"isShow\":true},\"name\":\"role\",\"parentId\":\"b1851d1b13594e71840103c11a37a002\",\"path\":\"/system/Role\",\"sort\":4},{\"component\":\"Layout\",\"icon\":\"Grid\",\"id\":\"b1851d1b13594e71840103c11a37a006\",\"isShow\":true,\"meta\":{\"keepAlive\":false,\"openMode\":0,\"id\":\"b1851d1b13594e71840103c11a37a006\",\"title\":\"用户管理\",\"isShow\":true},\"name\":\"user\",\"parentId\":\"b1851d1b13594e71840103c11a37a002\",\"path\":\"/system/User\",\"sort\":5}],\"component\":\"Layout\",\"icon\":\"Grid\",\"id\":\"b1851d1b13594e71840103c11a37a002\",\"isShow\":true,\"meta\":{\"keepAlive\":false,\"openMode\":0,\"id\":\"b1851d1b13594e71840103c11a37a002\",\"title\":\"系统管理\",\"isShow\":true},\"name\":\"system\",\"parentId\":\"0\",\"path\":\"/system\",\"sort\":1}]}', 49, '534a37c366ec47878a6b0c85703d0bc2', NULL, 0, '/tansci/sysmenu/menus', '127.0.0.1', NULL, NULL, '2023-04-07 14:50:17');
-- ----------------------------
-- Table structure for sys_org

View File

@ -69,4 +69,18 @@ export function logout(){
removeUser()
location.reload()
})
}
// 验证码
export function getCode(){
return new Promise((resolve, reject) => {
request({
url: '/tansci/auth/code',
method: 'get'
}).then((res:any) => {
resolve(res)
}).catch((e:any) => {
reject(e)
})
})
}

View File

@ -30,10 +30,10 @@ axiosInstance.interceptors.request.use((config: AxiosRequestConfig) => {
// axios实例拦截响应
axiosInstance.interceptors.response.use(
(response: AxiosResponse) => {
if (response.status === 200 && response.data.code == 200) {
if (response.status === 200 && response.data.code === 200) {
return response;
} else {
ElMessage.warning(showMessage(response.status));
ElMessage.warning(showMessage(response.data.code));
if (response.data.code === 402) {
logout()
}

View File

@ -1,14 +1,15 @@
<script setup lang="ts">
import {onBeforeMount,reactive,ref,toRefs} from "vue"
import {onBeforeMount,onMounted,reactive,ref,toRefs} from "vue"
import type {FormInstance} from 'element-plus'
import {useRouter} from 'vue-router'
import {login} from '@/api/auth'
import {login,getCode} from '@/api/auth'
const router = useRouter()
const loginFormRef = ref<FormInstance>()
const logo = new URL('../../assets/image/logo.png', import.meta.url).href
const loginLogo = new URL('../../assets/image/login-icon.png', import.meta.url).href
const codeImg = ref()
const state = reactive({
loading: false,
@ -18,6 +19,7 @@
loginForm: {
username: '',
password: '',
code: '',
remember: 0
},
})
@ -26,11 +28,21 @@
state.loginStyle.height = (document.body.clientHeight || document.documentElement.clientHeight) + "px"
})
onMounted(() =>{
onCode()
})
function copyYear(){
let date = new Date();
return date.getFullYear();
}
function onCode(){
getCode().then((res:any) =>{
codeImg.value = 'data:image/png;base64,' + res.data.result
})
}
async function onSubmit(formEl: FormInstance | undefined) {
if (!formEl) return;
await formEl.validate((valid)=>{
@ -38,7 +50,8 @@
// token
let param:any = {
username: state.loginForm.username,
password: state.loginForm.password
password: state.loginForm.password,
code: state.loginForm.code
}
state.loading = true;
login(param).then((res:any) =>{
@ -81,6 +94,10 @@
{required: true,message: '请输入密码',trigger: 'blur'}]">
<el-input type="password" v-model="state.loginForm.password" prefix-icon="Lock" show-password placeholder="请输入密码" style="width:100%"></el-input>
</el-form-item>
<el-form-item prop="code" :rules="[{required: true,message: '请输入验证码',trigger: 'blur'}]">
<el-input v-model="state.loginForm.code" prefix-icon="HelpFilled" placeholder="请输入验证码" style="width:70%; margin-right: 1%"></el-input>
<img :src="codeImg" @click="onCode" style="width: 29%; height: 38px;">
</el-form-item>
<el-form-item>
<el-checkbox v-model="state.loginForm.remember">记住密码</el-checkbox>
</el-form-item>

View File

@ -21,6 +21,8 @@
<druid-spring-boot.varsion>1.2.6</druid-spring-boot.varsion>
<sa-token-spring-boot.varsion>1.34.0</sa-token-spring-boot.varsion>
<knife4j-spring-boot.version>3.0.3</knife4j-spring-boot.version>
<hutool-all.version>5.7.22</hutool-all.version>
<fastjson2.version>2.0.26</fastjson2.version>
</properties>
<dependencies>
@ -29,6 +31,11 @@
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
@ -65,6 +72,17 @@
<version>${knife4j-spring-boot.version}</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool-all.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>${fastjson2.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>

View File

@ -0,0 +1,38 @@
package com.tansci.common.annotation;
import java.lang.annotation.*;
/**
* @ClassName Log.java
* @ClassPath com.tansci.common.annotation.Log.java
* @Description 自定义操作日志注解
* @Author tanyp
* @Date 2023/4/7 14:05
**/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log {
/**
* 操作模块
*
* @return
*/
String modul() default "";
/**
* 操作类型
*
* @return
*/
String type() default "";
/**
* 操作说明
*
* @return
*/
String desc() default "";
}

View File

@ -0,0 +1,180 @@
package com.tansci.common.aop;
import cn.dev33.satoken.stp.StpUtil;
import com.alibaba.fastjson2.JSON;
import com.tansci.common.annotation.Log;
import com.tansci.common.constant.Constants;
import com.tansci.domain.SysOperLog;
import com.tansci.domain.vo.SysUserSessionVo;
import com.tansci.service.SysOperLogService;
import com.tansci.utils.SystemUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
/**
* @ClassName OperLogAspect.java
* @ClassPath com.tansci.common.aop.OperLogAspect.java
* @Description 操作日志记录
* @Author tanyp
* @Date 2023/4/7 14:02
**/
@Slf4j
@Aspect
@Component
public class OperLogAspect {
/**
* 统计请求的处理时间
*/
ThreadLocal<Long> startTime = new ThreadLocal<>();
@Autowired
private SysOperLogService sysOperLogService;
/**
* @MonthName logPoinCut
* @Description 设置操作日志切入点 记录操作日志 在注解的位置切入代码
* @Author tanyp
* @Date 2023/4/7 14:06
* @Param []
* @return void
**/
@Pointcut("@annotation(com.tansci.common.annotation.Log)")
public void logPoinCut() {
}
/**
* @MonthName exceptionLogPoinCut
* @Description 设置操作异常切入点记录异常日志 扫描所有controller包下操作
* @Author tanyp
* @Date 2023/4/7 14:07
* @Param []
* @return void
**/
@Pointcut("execution(* com.tansci.controller..*.*(..))")
public void exceptionLogPoinCut() {
}
@Before("logPoinCut()")
public void doBefore() {
// 接收到请求记录请求开始时间
startTime.set(System.currentTimeMillis());
}
/**
* @MonthName doAfterReturning
* @Description 正常返回通知拦截用户操作日志连接点正常执行完成后执行 如果连接点抛出异常则不会执行
* @Author tanyp
* @Date 2023/4/7 14:08
* @Param [joinPoint, keys]
* @return void
**/
@AfterReturning(value = "logPoinCut()", returning = "keys")
public void doAfterReturning(JoinPoint joinPoint, Object keys) {
try {
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
SysUserSessionVo sessionVo = (SysUserSessionVo) StpUtil.getSession().get(String.valueOf(StpUtil.getLoginId()));
SysOperLog operLog = SysOperLog.builder()
.reqParam(JSON.toJSONString(converMap(request.getParameterMap())))
.resParam(JSON.toJSONString(keys))
.takeUpTime(System.currentTimeMillis() - startTime.get())
.userId(String.valueOf(StpUtil.getLoginId()))
.userName(sessionVo.getUsername())
.method(joinPoint.getTarget().getClass().getName() + "." + method.getName())
.uri(request.getRequestURI())
.ip(SystemUtils.getIp(request))
.status(Constants.OPER_LOG_STATUS_SUCCESS)
.createTime(LocalDateTime.now())
.build();
Log log = method.getAnnotation(Log.class);
if (Objects.nonNull(log)) {
operLog.setModule(log.modul());
operLog.setType(log.type());
operLog.setMessage(log.desc());
}
sysOperLogService.save(operLog);
} catch (Exception e) {
log.error("记录操作日志异常:{}", e);
}
}
/**
* @MonthName doAfterThrowing
* @Description 异常返回通知用于拦截异常日志信息 连接点抛出异常后执行
* @Author tanyp
* @Date 2023/4/7 14:36
* @Param [joinPoint, e]
* @return void
**/
@AfterThrowing(pointcut = "exceptionLogPoinCut()", throwing = "e")
public void doAfterThrowing(JoinPoint joinPoint, Throwable e) {
try {
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
SysUserSessionVo sessionVo = (SysUserSessionVo) StpUtil.getSession().get(String.valueOf(StpUtil.getLoginId()));
SysOperLog operLog = SysOperLog.builder()
.reqParam(JSON.toJSONString(converMap(request.getParameterMap())))
.takeUpTime(System.currentTimeMillis() - startTime.get())
.userId(String.valueOf(StpUtil.getLoginId()))
.userName(sessionVo.getUsername())
.method(joinPoint.getTarget().getClass().getName() + "." + method.getName())
.uri(request.getRequestURI())
.ip(SystemUtils.getIp(request))
.status(Constants.OPER_LOG_STATUS_ERROR)
.unusual(stackTraceToString(e.getClass().getName(), e.getMessage(), e.getStackTrace()))
.createTime(LocalDateTime.now())
.build();
Log log = method.getAnnotation(Log.class);
if (Objects.nonNull(log)) {
operLog.setModule(log.modul());
operLog.setType(log.type());
operLog.setMessage(log.desc());
}
sysOperLogService.save(operLog);
} catch (Exception e2) {
log.error("记录操作日志异常:{}", e2);
}
}
public Map<String, String> converMap(Map<String, String[]> paramMap) {
Map<String, String> rtnMap = new HashMap<>();
for (String key : paramMap.keySet()) {
rtnMap.put(key, paramMap.get(key)[0]);
}
return rtnMap;
}
public String stackTraceToString(String exceptionName, String exceptionMessage, StackTraceElement[] elements) {
StringBuffer strbuff = new StringBuffer();
for (StackTraceElement stet : elements) {
strbuff.append(stet + "<br/>");
}
String message = exceptionName + ":" + exceptionMessage + "<br/>" + strbuff.toString();
return message;
}
}

View File

@ -10,12 +10,23 @@ package com.tansci.common.constant;
public class Constants {
/**
* 删除状态
* 删除状态0正常1删除
*/
public final static Integer NOT_DEL_FALG = 0;
/**
* 已删除状态
*/
public final static Integer IS_DEL_FALG = 1;
/**
* 操作日志状态0成功1失败
*/
public final static Integer OPER_LOG_STATUS_SUCCESS = 0;
public final static Integer OPER_LOG_STATUS_ERROR = 1;
/**
* 接口操作类型
*/
public final static String SELECT = "SELECT";
public final static String INSERT = "INSERT";
public final static String UPDATE = "INSERT";
public final static String DELETE = "DELETE";
}

View File

@ -2,6 +2,8 @@ package com.tansci.controller;
import cn.dev33.satoken.session.SaSessionCustomUtil;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;
import com.tansci.common.WrapMapper;
import com.tansci.common.Wrapper;
import com.tansci.domain.SysUser;
@ -13,6 +15,8 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
/**
* @ClassName AuthController.java
* @ClassPath com.tansci.controller.AuthController.java
@ -31,8 +35,8 @@ public class AuthController {
@ApiOperation(value = "登录", notes = "登录")
@PostMapping("/login")
public Wrapper<SysUserVo> login(@RequestBody SysUser user) {
return WrapMapper.wrap(Wrapper.SUCCESS_CODE, Wrapper.SUCCESS_MESSAGE, sysUserService.login(user));
public Wrapper<SysUserVo> login(HttpServletRequest request, @RequestBody SysUser user) {
return WrapMapper.wrap(Wrapper.SUCCESS_CODE, Wrapper.SUCCESS_MESSAGE, sysUserService.login(request, user));
}
@ApiOperation(value = "登出", notes = "登出")
@ -43,4 +47,16 @@ public class AuthController {
return WrapMapper.wrap(Wrapper.SUCCESS_CODE, Wrapper.SUCCESS_MESSAGE, "登出成功!");
}
@ApiOperation(value = "验证码", notes = "验证码")
@GetMapping("/code")
public Wrapper<Object> verificationCode(HttpServletRequest request) {
LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(100, 60);
// 四则运算方式
// lineCaptcha.setGenerator(new MathGenerator());
// 验证码存session 60秒过期
request.getSession().setMaxInactiveInterval(60);
request.getSession().setAttribute("verifyCode", lineCaptcha.getCode());
return WrapMapper.wrap(Wrapper.SUCCESS_CODE, Wrapper.SUCCESS_MESSAGE, lineCaptcha.getImageBase64());
}
}

View File

@ -2,6 +2,8 @@ package com.tansci.controller;
import com.tansci.common.WrapMapper;
import com.tansci.common.Wrapper;
import com.tansci.common.annotation.Log;
import com.tansci.common.constant.Constants;
import com.tansci.domain.SysMenu;
import com.tansci.domain.vo.SysMenuVo;
import com.tansci.service.SysMenuService;
@ -32,12 +34,14 @@ public class SysMenuController {
private SysMenuService sysMenuService;
@ApiOperation(value = "当前用户权限菜单树", notes = "当前用户权限菜单树")
@Log(modul = "菜单管理-当前用户权限菜单树", type = Constants.SELECT, desc = "当前用户权限菜单树")
@GetMapping("/tree")
public Wrapper<List<SysMenu>> tree(SysMenu menu) {
return WrapMapper.wrap(Wrapper.SUCCESS_CODE, Wrapper.SUCCESS_MESSAGE, sysMenuService.tree(menu));
}
@ApiOperation(value = "当前用户权限菜单列表", notes = "当前用户权限菜单列表")
@Log(modul = "菜单管理-当前用户权限菜单列表", type = Constants.SELECT, desc = "当前用户权限菜单列表")
@GetMapping("/menus")
public Wrapper<List<SysMenuVo>> menus() {
return WrapMapper.wrap(Wrapper.SUCCESS_CODE, Wrapper.SUCCESS_MESSAGE, sysMenuService.menus());

View File

@ -4,6 +4,8 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tansci.common.WrapMapper;
import com.tansci.common.Wrapper;
import com.tansci.common.annotation.Log;
import com.tansci.common.constant.Constants;
import com.tansci.domain.SysUser;
import com.tansci.service.SysUserService;
import io.swagger.annotations.Api;
@ -31,36 +33,42 @@ public class SysUserController {
private SysUserService sysUserService;
@ApiOperation(value = "用户分页", notes = "用户分页")
@Log(modul = "用户管理-用户分页", type = Constants.SELECT, desc = "用户分页")
@GetMapping("/page")
public Wrapper<IPage<SysUser>> page(Page page, SysUser user) {
return WrapMapper.wrap(Wrapper.SUCCESS_CODE, Wrapper.SUCCESS_MESSAGE, sysUserService.page(page, user));
}
@ApiOperation(value = "用户列表", notes = "用户列表")
@Log(modul = "用户管理-用户列表", type = Constants.SELECT, desc = "用户列表")
@GetMapping("/list")
public Wrapper<List<SysUser>> list(SysUser user) {
return WrapMapper.wrap(Wrapper.SUCCESS_CODE, Wrapper.SUCCESS_MESSAGE, sysUserService.list(user));
}
@ApiOperation(value = "添加用户信息", notes = "添加用户信息")
@Log(modul = "用户管理-添加用户信息", type = Constants.INSERT, desc = "添加用户信息")
@PostMapping("/save")
public Wrapper<Object> save(@RequestBody SysUser user) {
return WrapMapper.wrap(Wrapper.SUCCESS_CODE, Wrapper.SUCCESS_MESSAGE, sysUserService.insert(user));
}
@ApiOperation(value = "修改用户信息", notes = "修改用户信息")
@Log(modul = "用户管理-修改用户信息", type = Constants.UPDATE, desc = "修改用户信息")
@PostMapping("/update")
public Wrapper<Object> update(@RequestBody SysUser user) {
return WrapMapper.wrap(Wrapper.SUCCESS_CODE, Wrapper.SUCCESS_MESSAGE, sysUserService.update(user));
}
@ApiOperation(value = "删除用户", notes = "删除用户")
@Log(modul = "用户管理-删除用户", type = Constants.DELETE, desc = "删除用户")
@GetMapping("/del")
public Wrapper<Object> del(SysUser user) {
return WrapMapper.wrap(Wrapper.SUCCESS_CODE, Wrapper.SUCCESS_MESSAGE, sysUserService.del(user));
}
@ApiOperation(value = "修改密码", notes = "修改密码")
@Log(modul = "用户管理-修改密码", type = Constants.UPDATE, desc = "修改密码")
@PostMapping("/modifyPass")
public Wrapper<Object> modifyPass(@RequestBody SysUser user) {
return WrapMapper.wrap(Wrapper.SUCCESS_CODE, Wrapper.SUCCESS_MESSAGE, sysUserService.modifyPass(user));

View File

@ -54,6 +54,9 @@ public class SysOperLog {
@ApiModelProperty(value = "操作用户id")
private String userId;
@ApiModelProperty(value = "状态0、成功1、失败")
private Integer status;
@ApiModelProperty(value = "操作用户名称")
private String userName;
@ -69,6 +72,9 @@ public class SysOperLog {
@ApiModelProperty(value = "版本号")
private String version;
@ApiModelProperty(value = "异常信息")
private String unusual;
@ApiModelProperty(value = "创建时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", locale = "zh", timezone = "GMT+8")
private LocalDateTime createTime;

View File

@ -98,4 +98,8 @@ public class SysUser {
@ApiModelProperty(value = "权限IDS")
private List<String> roleIds;
@TableField(exist = false)
@ApiModelProperty(value = "验证码")
private String code;
}

View File

@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.extension.service.IService;
import com.tansci.domain.SysUser;
import com.tansci.domain.vo.SysUserVo;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
/**
@ -27,7 +28,7 @@ public interface SysUserService extends IService<SysUser> {
Object del(SysUser user);
SysUserVo login(SysUser user);
SysUserVo login(HttpServletRequest request, SysUser user);
Object modifyPass(SysUser user);

View File

@ -8,18 +8,22 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.tansci.common.constant.Constants;
import com.tansci.common.exception.BusinessException;
import com.tansci.domain.SysLoginLog;
import com.tansci.domain.SysUser;
import com.tansci.domain.SysUserRole;
import com.tansci.domain.vo.SysUserSessionVo;
import com.tansci.domain.vo.SysUserVo;
import com.tansci.mapper.SysUserMapper;
import com.tansci.service.SysLoginLogService;
import com.tansci.service.SysUserRoleService;
import com.tansci.service.SysUserService;
import com.tansci.utils.Sha256Util;
import com.tansci.utils.SystemUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
@ -38,6 +42,8 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
@Autowired
private SysUserRoleService sysUserRoleService;
@Autowired
private SysLoginLogService sysLoginLogService;
@Override
public IPage<SysUser> page(Page page, SysUser user) {
@ -98,11 +104,35 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
}
@Override
public SysUserVo login(SysUser user) {
SysUser sysUser = this.baseMapper.selectOne(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getUsername, user.getUsername()));
if (Objects.nonNull(sysUser) && Objects.equals(sysUser.getPassword(), Sha256Util.getSHA256(user.getPassword()))) {
public SysUserVo login(HttpServletRequest request, SysUser user) {
SysLoginLog loginLog = SysLoginLog.builder()
.username(user.getUsername())
.failPassword(user.getPassword())
.type("成功")
.ip(SystemUtils.getIp(request))
.address(SystemUtils.getAddress(request))
.browser(SystemUtils.getBrowser(request))
.os(SystemUtils.getOS(request))
.build();
try {
// 校验验证码
String code = (String) request.getSession().getAttribute("verifyCode");
if (Objects.isNull(user.getCode()) || !Objects.equals(code, user.getCode())) {
loginLog.setType("失败");
throw new BusinessException("验证码有误,请重新获取!");
}
SysUser sysUser = this.baseMapper.selectOne(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getUsername, user.getUsername()));
if (Objects.isNull(sysUser) && !Objects.equals(sysUser.getPassword(), Sha256Util.getSHA256(user.getPassword()))) {
loginLog.setType("失败");
throw new BusinessException("登录失败,用户名或密码有误!");
}
// 生成token
StpUtil.login(sysUser.getId());
// 登录日志记录
loginLog.setToken(StpUtil.getTokenInfo().getTokenValue());
// 用户角色到session
List<SysUserRole> roles = sysUserRoleService.list(Wrappers.<SysUserRole>lambdaQuery().eq(SysUserRole::getUserId, sysUser.getId()));
@ -126,8 +156,9 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
.loginTime(LocalDateTime.now())
.token(StpUtil.getTokenInfo().getTokenValue())
.build();
} finally {
sysLoginLogService.save(loginLog);
}
return null;
}
@Override

View File

@ -1,5 +1,11 @@
package com.tansci.utils;
import cn.hutool.core.net.Ipv4Util;
import cn.hutool.http.HttpUtil;
import cn.hutool.http.useragent.UserAgent;
import cn.hutool.http.useragent.UserAgentUtil;
import cn.hutool.json.JSONUtil;
import javax.servlet.http.HttpServletRequest;
/**
@ -20,48 +26,8 @@ public class SystemUtils {
* @return java.lang.String
**/
public static String getOS(HttpServletRequest request) {
String osName = "";
String userAgent = request.getHeader("User-Agent").toUpperCase();
if (userAgent.contains("WINDOWS")) {
if (userAgent.contains("WINDOWS NT 10.0")) {
osName = "Windows 10";
} else if (userAgent.contains("WINDOWS NT 6.3")) {
osName = "Windows 8.1";
} else if (userAgent.contains("WINDOWS NT 6.2")) {
osName = "Windows 8";
} else if (userAgent.contains("WINDOWS NT 6.1")) {
osName = "Windows 7";
} else if (userAgent.contains("WINDOWS NT 6.0")) {
osName = "Windows Vista";
} else if (userAgent.contains("WINDOWS NT 5.2")) {
osName = "Windows XP";
} else if (userAgent.contains("WINDOWS NT 5.1")) {
osName = "Windows XP";
} else if (userAgent.contains("WINDOWS NT 5.01")) {
osName = "Windows 2000";
} else if (userAgent.contains("WINDOWS NT 5.0")) {
osName = "Windows 2000";
} else if (userAgent.contains("WINDOWS NT 4.0")) {
osName = "Windows NT 4.0";
} else if (userAgent.contains("WINDOWS 98; WIN 9X 4.90")) {
osName = "Windows ME";
} else if (userAgent.contains("WINDOWS 98")) {
osName = "Windows 98";
} else if (userAgent.contains("WINDOWS 95")) {
osName = "Windows 95";
} else if (userAgent.contains("WINDOWS CE")) {
osName = "Windows CE";
}
} else if (userAgent.contains("MAC")) {
osName = "Mac";
} else if (userAgent.contains("UNIX")) {
osName = "UNIX";
} else if (userAgent.contains("LINUX")) {
osName = "Linux";
} else if (userAgent.contains("SUNOS")) {
osName = "SunOS";
}
return osName;
UserAgent userAgent = UserAgentUtil.parse(request.getHeaders("User-Agent").toString());
return userAgent.getBrowser().toString();
}
/**
@ -73,31 +39,12 @@ public class SystemUtils {
* @return java.lang.String
**/
public static String getBrowser(HttpServletRequest request) {
String browserName = "";
String userAgent = request.getHeader("User-Agent").toUpperCase();
if (userAgent == null || userAgent.equals("")) {
return "";
}
if (userAgent.indexOf("MSIE") > 0) {
browserName = "IE";
} else if (userAgent.indexOf("FIREFOX") > 0) {
browserName = "Firefox";
} else if (userAgent.indexOf("CHROME") > 0) {
browserName = "Chrome";
} else if (userAgent.indexOf("SAFARI") > 0) {
browserName = "Safari";
} else if (userAgent.indexOf("CAMINO") > 0) {
browserName = "Camino";
} else if (userAgent.indexOf("KONQUEROR") > 0) {
browserName = "Konqueror";
} else if (userAgent.indexOf("EDGE") > 0) {
browserName = "Microsoft Edge";
}
return browserName;
UserAgent userAgent = UserAgentUtil.parse(request.getHeaders("User-Agent").toString());
return userAgent.getOs().toString();
}
/**
* @methodNamegetIpAddress
* @methodNamegetIp
* @description获取IP地址
* @authortanyp
* @dateTime2022/2/15 14:19
@ -105,7 +52,7 @@ public class SystemUtils {
* @Return java.lang.String
* @editNote
*/
public static String getIpAddress(HttpServletRequest request) {
public static String getIp(HttpServletRequest request) {
String ip = request.getHeader("X-Forwarded-For");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
@ -148,4 +95,26 @@ public class SystemUtils {
}
}
/**
* @MonthName getAddress
* @Description 获取地址
* @Author tanyp
* @Date 2023/4/7 11:24
* @Param [ip]
* @return java.lang.String
**/
public static String getAddress(HttpServletRequest request) {
String ip = getIp(request);
try {
if (Ipv4Util.isInnerIP(ip)) {
return "内网IP";
}
return JSONUtil.parseObj(HttpUtil.get("https://whois.pconline.com.cn/ipJson.jsp?json=true&ip=" + ip)).getStr("addr");
} catch (IllegalArgumentException e) {
return "内网IP";
} catch (Exception e) {
return "未知";
}
}
}