新增登录日志功能
This commit is contained in:
parent
16f0ba8771
commit
9e515b1d62
|
|
@ -270,48 +270,6 @@ COMMENT ON COLUMN sys_role_data_scope.create_time IS '创建时间';
|
|||
COMMENT ON COLUMN sys_role_data_scope.updater IS '更新者';
|
||||
COMMENT ON COLUMN sys_role_data_scope.update_time IS '更新时间';
|
||||
|
||||
CREATE TABLE sys_oauth_client (
|
||||
id bigint IDENTITY NOT NULL,
|
||||
client_id varchar(256),
|
||||
client_secret varchar(256),
|
||||
resource_ids varchar(256),
|
||||
scope varchar(256),
|
||||
authorized_grant_types varchar(256),
|
||||
web_server_redirect_uri varchar(256),
|
||||
authorities varchar(256),
|
||||
access_token_validity int,
|
||||
refresh_token_validity int,
|
||||
additional_information varchar(4096),
|
||||
autoapprove varchar(128),
|
||||
version int,
|
||||
deleted int,
|
||||
creator bigint,
|
||||
create_time datetime,
|
||||
updater bigint,
|
||||
update_time datetime,
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE sys_oauth_client IS '客户端管理';
|
||||
COMMENT ON COLUMN sys_oauth_client.id IS 'id';
|
||||
COMMENT ON COLUMN sys_oauth_client.client_id IS '客户端id';
|
||||
COMMENT ON COLUMN sys_oauth_client.client_secret IS '客户端密钥';
|
||||
COMMENT ON COLUMN sys_oauth_client.resource_ids IS '资源ids';
|
||||
COMMENT ON COLUMN sys_oauth_client.scope IS '授权范围';
|
||||
COMMENT ON COLUMN sys_oauth_client.authorized_grant_types IS '授权类型';
|
||||
COMMENT ON COLUMN sys_oauth_client.web_server_redirect_uri IS '回调地址';
|
||||
COMMENT ON COLUMN sys_oauth_client.authorities IS '回调地址';
|
||||
COMMENT ON COLUMN sys_oauth_client.access_token_validity IS '访问令牌有效期';
|
||||
COMMENT ON COLUMN sys_oauth_client.refresh_token_validity IS '刷新令牌有效期';
|
||||
COMMENT ON COLUMN sys_oauth_client.additional_information IS '附加信息';
|
||||
COMMENT ON COLUMN sys_oauth_client.autoapprove IS '自动授权';
|
||||
COMMENT ON COLUMN sys_oauth_client.version IS '版本号';
|
||||
COMMENT ON COLUMN sys_oauth_client.deleted IS '删除标识 0:正常 1:已删除';
|
||||
COMMENT ON COLUMN sys_oauth_client.creator IS '创建者';
|
||||
COMMENT ON COLUMN sys_oauth_client.create_time IS '创建时间';
|
||||
COMMENT ON COLUMN sys_oauth_client.updater IS '更新者';
|
||||
COMMENT ON COLUMN sys_oauth_client.update_time IS '更新时间';
|
||||
|
||||
create table sys_dict_type
|
||||
(
|
||||
id bigint IDENTITY NOT NULL,
|
||||
|
|
@ -372,13 +330,34 @@ COMMENT ON COLUMN sys_dict_data.create_time IS '创建时间';
|
|||
COMMENT ON COLUMN sys_dict_data.updater IS '更新者';
|
||||
COMMENT ON COLUMN sys_dict_data.update_time IS '更新时间';
|
||||
|
||||
create table sys_log_login
|
||||
(
|
||||
id bigint IDENTITY NOT NULL,
|
||||
username varchar(50),
|
||||
ip varchar(32),
|
||||
address varchar(32),
|
||||
user_agent varchar(500),
|
||||
status int,
|
||||
operation int,
|
||||
create_time datetime,
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE sys_log_login IS '登录日志';
|
||||
COMMENT ON COLUMN sys_log_login.id IS 'id';
|
||||
COMMENT ON COLUMN sys_log_login.username IS '用户名';
|
||||
COMMENT ON COLUMN sys_log_login.ip IS '登录IP';
|
||||
COMMENT ON COLUMN sys_log_login.address IS '登录地点';
|
||||
COMMENT ON COLUMN sys_log_login.user_agent IS 'User Agent';
|
||||
COMMENT ON COLUMN sys_log_login.status IS '登录状态 0:失败 1:成功';
|
||||
COMMENT ON COLUMN sys_log_login.operation IS '操作信息 0:登录成功 1:退出成功 2:验证码错误 3:账号密码错误';
|
||||
COMMENT ON COLUMN sys_log_login.create_time IS '创建时间';
|
||||
|
||||
|
||||
|
||||
SET IDENTITY_INSERT sys_user ON;
|
||||
INSERT INTO sys_user (id, username, password, real_name, avatar, gender, email, mobile, status, org_id, super_admin, version, deleted, creator, create_time, updater, update_time) VALUES (10000, 'admin', '{bcrypt}$2a$10$mW/yJPHjyueQ1g26WNBz0uxVPa0GQdJO1fFZmqdkqgMTGnyszlXxu', 'admin', 'https://cdn.maku.net/images/avatar.png', 0, 'babamu@126.com', '13612345678', 1, null, 1, 0, 0, 10000, now(), 10000, now());
|
||||
|
||||
SET IDENTITY_INSERT sys_oauth_client ON;
|
||||
INSERT INTO sys_oauth_client (id, client_id, client_secret, resource_ids, scope, authorized_grant_types, web_server_redirect_uri, authorities, access_token_validity, refresh_token_validity, additional_information, autoapprove, version, deleted, creator, create_time, updater, update_time) VALUES (1, 'web', '123456', '', 'all', '["authorization_code","password","implicit","client_credentials","refresh_token"]', 'https://gitee.com/makunet', NULL, 43200, 604800, NULL, 'true', 0, 0, 10000, now(), 10000, now());
|
||||
|
||||
SET IDENTITY_INSERT sys_menu ON;
|
||||
INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (1, 0, '系统设置', NULL, NULL, 0, 0, 'icon-setting', 1, 0, 0, 10000, now(), 10000, now());
|
||||
INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (2, 1, '菜单管理', 'sys/menu/index', NULL, 0, 0, 'icon-menu', 0, 0, 0, 10000, now(), 10000, now());
|
||||
|
|
|
|||
|
|
@ -153,28 +153,6 @@ create table sys_role_data_scope
|
|||
key idx_role_id (role_id)
|
||||
) ENGINE = InnoDB DEFAULT CHARACTER SET utf8mb4 COMMENT ='角色数据权限';
|
||||
|
||||
CREATE TABLE sys_oauth_client (
|
||||
id bigint NOT NULL AUTO_INCREMENT COMMENT 'id',
|
||||
client_id varchar(256) NOT NULL COMMENT '客户端id',
|
||||
client_secret varchar(256) COMMENT '客户端密钥',
|
||||
resource_ids varchar(256) COMMENT '资源ids',
|
||||
scope varchar(256) COMMENT '授权范围',
|
||||
authorized_grant_types varchar(256) COMMENT '授权类型',
|
||||
web_server_redirect_uri varchar(256) COMMENT '回调地址',
|
||||
authorities varchar(256) COMMENT '权限标识',
|
||||
access_token_validity int COMMENT '访问令牌有效期',
|
||||
refresh_token_validity int COMMENT '刷新令牌有效期',
|
||||
additional_information varchar(4096) COMMENT '附加信息',
|
||||
autoapprove varchar(128) COMMENT '自动授权',
|
||||
version int COMMENT '版本号',
|
||||
deleted tinyint COMMENT '删除标识 0:正常 1:已删除',
|
||||
creator bigint COMMENT '创建者',
|
||||
create_time datetime COMMENT '创建时间',
|
||||
updater bigint COMMENT '更新者',
|
||||
update_time datetime COMMENT '更新时间',
|
||||
PRIMARY KEY (id)
|
||||
) ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4 COMMENT='客户端管理';
|
||||
|
||||
create table sys_dict_type
|
||||
(
|
||||
id bigint NOT NULL AUTO_INCREMENT COMMENT 'id',
|
||||
|
|
@ -225,9 +203,22 @@ create table sys_attachment
|
|||
) ENGINE = InnoDB DEFAULT CHARACTER SET utf8mb4 COMMENT ='附件管理';
|
||||
|
||||
|
||||
create table sys_log_login
|
||||
(
|
||||
id bigint NOT NULL AUTO_INCREMENT COMMENT 'id',
|
||||
username varchar(50) NOT NULL COMMENT '用户名',
|
||||
ip varchar(32) COMMENT '登录IP',
|
||||
address varchar(32) COMMENT '登录地点',
|
||||
user_agent varchar(500) COMMENT 'User Agent',
|
||||
status tinyint COMMENT '登录状态 0:失败 1:成功',
|
||||
operation tinyint unsigned COMMENT '操作信息 0:登录成功 1:退出成功 2:验证码错误 3:账号密码错误',
|
||||
create_time datetime COMMENT '创建时间',
|
||||
primary key (id)
|
||||
) ENGINE = InnoDB DEFAULT CHARACTER SET utf8mb4 COMMENT ='登录日志';
|
||||
|
||||
|
||||
|
||||
INSERT INTO sys_user (id, username, password, real_name, avatar, gender, email, mobile, status, org_id, super_admin, version, deleted, creator, create_time, updater, update_time) VALUES (10000, 'admin', '{bcrypt}$2a$10$mW/yJPHjyueQ1g26WNBz0uxVPa0GQdJO1fFZmqdkqgMTGnyszlXxu', 'admin', 'https://cdn.maku.net/images/avatar.png', 0, 'babamu@126.com', '13612345678', 1, null, 1, 0, 0, 10000, now(), 10000, now());
|
||||
INSERT INTO sys_oauth_client (id, client_id, client_secret, resource_ids, scope, authorized_grant_types, web_server_redirect_uri, authorities, access_token_validity, refresh_token_validity, additional_information, autoapprove, version, deleted, creator, create_time, updater, update_time) VALUES (1, 'web', '123456', '', 'all', '["authorization_code","password","implicit","client_credentials","refresh_token"]', 'https://gitee.com/makunet', NULL, 43200, 604800, NULL, 'true', 0, 0, 10000, now(), 10000, now());
|
||||
|
||||
INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (1, 0, '系统设置', NULL, NULL, 0, 0, 'icon-setting', 1, 0, 0, 10000, now(), 10000, now());
|
||||
INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (2, 1, '菜单管理', 'sys/menu/index', NULL, 0, 0, 'icon-menu', 0, 0, 0, 10000, now(), 10000, now());
|
||||
|
|
@ -241,12 +232,12 @@ INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sor
|
|||
INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (10, 7, '修改', '', 'sys:dict:update,sys:dict:info', 1, 0, '', 1, 0, 0, 10000, now(), 10000, now());
|
||||
INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (11, 7, '删除', '', 'sys:dict:delete', 1, 0, '', 3, 0, 0, 10000, now(), 10000, now());
|
||||
INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (12, 0, '权限管理', '', '', 0, 0, 'icon-safetycertificate', 0, 0, 0, 10000, now(), 10000, now());
|
||||
INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (13, 12, '岗位管理', 'sys/post/index', '', 0, 0, 'icon-addteam', 2, 0, 0, 10000, now(), 10000, now());
|
||||
INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (13, 12, '岗位管理', 'sys/post/index', '', 0, 0, 'icon-solution', 2, 0, 0, 10000, now(), 10000, now());
|
||||
INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (14, 13, '查询', '', 'sys:post:page', 1, 0, '', 0, 0, 0, 10000, now(), 10000, now());
|
||||
INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (15, 13, '新增', '', 'sys:post:save', 1, 0, '', 1, 0, 0, 10000, now(), 10000, now());
|
||||
INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (16, 13, '修改', '', 'sys:post:update,sys:post:info', 1, 0, '', 2, 0, 0, 10000, now(), 10000, now());
|
||||
INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (17, 13, '删除', '', 'sys:post:delete', 1, 0, '', 3, 0, 0, 10000, now(), 10000, now());
|
||||
INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (18, 12, '机构管理', 'sys/org/index', '', 0, 0, 'icon-team', 1, 0, 0, 10000, now(), 10000, now());
|
||||
INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (18, 12, '机构管理', 'sys/org/index', '', 0, 0, 'icon-cluster', 1, 0, 0, 10000, now(), 10000, now());
|
||||
INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (19, 18, '查询', '', 'sys:org:list', 1, 0, '', 0, 0, 0, 10000, now(), 10000, now());
|
||||
INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (20, 18, '新增', '', 'sys:org:save', 1, 0, '', 1, 0, 0, 10000, now(), 10000, now());
|
||||
INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (21, 18, '修改', '', 'sys:org:update,sys:org:info', 1, 0, '', 2, 0, 0, 10000, now(), 10000, now());
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
package net.maku.system.controller;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.AllArgsConstructor;
|
||||
import net.maku.framework.common.page.PageResult;
|
||||
import net.maku.framework.common.utils.Result;
|
||||
import net.maku.system.query.SysLogLoginQuery;
|
||||
import net.maku.system.service.SysLogLoginService;
|
||||
import net.maku.system.vo.SysLogLoginVO;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
/**
|
||||
* 登录日志
|
||||
*
|
||||
* @author 阿沐 babamu@126.com
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("sys/log/login")
|
||||
@Tag(name = "登录日志")
|
||||
@AllArgsConstructor
|
||||
public class SysLogLoginController {
|
||||
private final SysLogLoginService sysLogLoginService;
|
||||
|
||||
@GetMapping("page")
|
||||
@Operation(summary = "分页")
|
||||
@PreAuthorize("hasAuthority('sys:log:login')")
|
||||
public Result<PageResult<SysLogLoginVO>> page(@Valid SysLogLoginQuery query) {
|
||||
PageResult<SysLogLoginVO> page = sysLogLoginService.page(query);
|
||||
|
||||
return Result.ok(page);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package net.maku.system.convert;
|
||||
|
||||
import net.maku.system.entity.SysLogLoginEntity;
|
||||
import net.maku.system.vo.SysLogLoginVO;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 登录日志
|
||||
*
|
||||
* @author 阿沐 babamu@126.com
|
||||
*/
|
||||
@Mapper
|
||||
public interface SysLogLoginConvert {
|
||||
SysLogLoginConvert INSTANCE = Mappers.getMapper(SysLogLoginConvert.class);
|
||||
|
||||
SysLogLoginEntity convert(SysLogLoginVO vo);
|
||||
|
||||
SysLogLoginVO convert(SysLogLoginEntity entity);
|
||||
|
||||
List<SysLogLoginVO> convertList(List<SysLogLoginEntity> list);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package net.maku.system.dao;
|
||||
|
||||
import net.maku.framework.common.dao.BaseDao;
|
||||
import net.maku.system.entity.SysLogLoginEntity;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* 登录日志
|
||||
*
|
||||
* @author 阿沐 babamu@126.com
|
||||
*/
|
||||
@Mapper
|
||||
public interface SysLogLoginDao extends BaseDao<SysLogLoginEntity> {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
package net.maku.system.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.FieldFill;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 登录日志
|
||||
*
|
||||
* @author 阿沐 babamu@126.com
|
||||
*/
|
||||
@Data
|
||||
@TableName("sys_log_login")
|
||||
public class SysLogLoginEntity {
|
||||
/**
|
||||
* id
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户名
|
||||
*/
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* 登录IP
|
||||
*/
|
||||
private String ip;
|
||||
|
||||
/**
|
||||
* 登录地点
|
||||
*/
|
||||
private String address;
|
||||
|
||||
/**
|
||||
* User Agent
|
||||
*/
|
||||
private String userAgent;
|
||||
|
||||
/**
|
||||
* 登录状态 0:失败 1:成功
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 操作信息 0:登录成功 1:退出成功 2:验证码错误 3:账号密码错误
|
||||
*/
|
||||
private Integer operation;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private Date createTime;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
package net.maku.system.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 登录信息
|
||||
*
|
||||
* @author 阿沐 babamu@126.com
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum LoginOperationEnum {
|
||||
/**
|
||||
* 登录成功
|
||||
*/
|
||||
LOGIN_SUCCESS(0),
|
||||
/**
|
||||
* 退出成功
|
||||
*/
|
||||
LOGOUT_SUCCESS(1),
|
||||
/**
|
||||
* 验证码错误
|
||||
*/
|
||||
CAPTCHA_FAIL(2),
|
||||
/**
|
||||
* 账号密码错误
|
||||
*/
|
||||
ACCOUNT_FAIL(3);
|
||||
|
||||
private final int value;
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package net.maku.system.query;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import net.maku.framework.common.query.Query;
|
||||
|
||||
/**
|
||||
* 登录日志查询
|
||||
*
|
||||
* @author 阿沐 babamu@126.com
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Schema(description = "登录日志查询")
|
||||
public class SysLogLoginQuery extends Query {
|
||||
@Schema(description = "用户名")
|
||||
private String username;
|
||||
|
||||
@Schema(description = "登录地点")
|
||||
private String address;
|
||||
|
||||
@Schema(description = "登录状态 0:失败 1:成功")
|
||||
private Integer status;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package net.maku.system.service;
|
||||
|
||||
import net.maku.framework.common.page.PageResult;
|
||||
import net.maku.framework.common.service.BaseService;
|
||||
import net.maku.system.entity.SysLogLoginEntity;
|
||||
import net.maku.system.query.SysLogLoginQuery;
|
||||
import net.maku.system.vo.SysLogLoginVO;
|
||||
|
||||
/**
|
||||
* 登录日志
|
||||
*
|
||||
* @author 阿沐 babamu@126.com
|
||||
*/
|
||||
public interface SysLogLoginService extends BaseService<SysLogLoginEntity> {
|
||||
|
||||
PageResult<SysLogLoginVO> page(SysLogLoginQuery query);
|
||||
|
||||
/**
|
||||
* 保存登录日志
|
||||
*
|
||||
* @param username 用户名
|
||||
* @param status 登录状态
|
||||
* @param operation 操作信息
|
||||
*/
|
||||
void save(String username, Integer status, Integer operation);
|
||||
}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
package net.maku.system.service.impl;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import lombok.AllArgsConstructor;
|
||||
import net.maku.framework.common.page.PageResult;
|
||||
import net.maku.framework.common.service.impl.BaseServiceImpl;
|
||||
import net.maku.framework.common.utils.AddressUtils;
|
||||
import net.maku.framework.common.utils.HttpContextUtils;
|
||||
import net.maku.framework.common.utils.IpUtils;
|
||||
import net.maku.system.convert.SysLogLoginConvert;
|
||||
import net.maku.system.dao.SysLogLoginDao;
|
||||
import net.maku.system.entity.SysLogLoginEntity;
|
||||
import net.maku.system.query.SysLogLoginQuery;
|
||||
import net.maku.system.service.SysLogLoginService;
|
||||
import net.maku.system.vo.SysLogLoginVO;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* 登录日志
|
||||
*
|
||||
* @author 阿沐 babamu@126.com
|
||||
*/
|
||||
@Service
|
||||
@AllArgsConstructor
|
||||
public class SysLogLoginServiceImpl extends BaseServiceImpl<SysLogLoginDao, SysLogLoginEntity> implements SysLogLoginService {
|
||||
|
||||
@Override
|
||||
public PageResult<SysLogLoginVO> page(SysLogLoginQuery query) {
|
||||
IPage<SysLogLoginEntity> page = baseMapper.selectPage(getPage(query), getWrapper(query));
|
||||
|
||||
return new PageResult<>(SysLogLoginConvert.INSTANCE.convertList(page.getRecords()), page.getTotal());
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<SysLogLoginEntity> getWrapper(SysLogLoginQuery query) {
|
||||
LambdaQueryWrapper<SysLogLoginEntity> wrapper = Wrappers.lambdaQuery();
|
||||
wrapper.like(StrUtil.isNotBlank(query.getUsername()), SysLogLoginEntity::getUsername, query.getUsername());
|
||||
wrapper.like(StrUtil.isNotBlank(query.getAddress()), SysLogLoginEntity::getAddress, query.getAddress());
|
||||
wrapper.like(query.getStatus() != null, SysLogLoginEntity::getStatus, query.getStatus());
|
||||
wrapper.orderByDesc(SysLogLoginEntity::getId);
|
||||
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(String username, Integer status, Integer operation) {
|
||||
HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
|
||||
assert request != null;
|
||||
String userAgent = request.getHeader(HttpHeaders.USER_AGENT);
|
||||
String ip = IpUtils.getIpAddr(request);
|
||||
String address = AddressUtils.getAddressByIP(ip);
|
||||
|
||||
SysLogLoginEntity entity = new SysLogLoginEntity();
|
||||
entity.setUsername(username);
|
||||
entity.setStatus(status);
|
||||
entity.setOperation(operation);
|
||||
entity.setIp(ip);
|
||||
entity.setAddress(address);
|
||||
entity.setUserAgent(userAgent);
|
||||
|
||||
baseMapper.insert(entity);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
package net.maku.system.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import net.maku.framework.common.utils.DateUtils;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 登录日志
|
||||
*
|
||||
* @author 阿沐 babamu@126.com
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "登录日志")
|
||||
public class SysLogLoginVO implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "id")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "用户名")
|
||||
private String username;
|
||||
|
||||
@Schema(description = "登录IP")
|
||||
private String ip;
|
||||
|
||||
@Schema(description = "登录地点")
|
||||
private String address;
|
||||
|
||||
@Schema(description = "User Agent")
|
||||
private String userAgent;
|
||||
|
||||
@Schema(description = "登录状态 0:失败 1:成功")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "操作信息 0:登录成功 1:退出成功 2:验证码错误 3:账号密码错误")
|
||||
private Integer operation;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
@JsonFormat(pattern = DateUtils.DATE_TIME_PATTERN)
|
||||
private Date createTime;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?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="net.maku.system.dao.SysLogLoginDao">
|
||||
|
||||
</mapper>
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
package net.maku.framework.common.utils;
|
||||
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 获取真实地址
|
||||
*
|
||||
* @author 阿沐 babamu@126.com
|
||||
*/
|
||||
@Slf4j
|
||||
public class AddressUtils {
|
||||
// 实时查询
|
||||
public static final String ADDRESS_URL = "https://whois.pconline.com.cn/ipJson.jsp";
|
||||
public static final String UNKNOWN = "未知";
|
||||
|
||||
public static String getAddressByIP(String ip) {
|
||||
// 内网
|
||||
if (IpUtils.internalIp(ip)) {
|
||||
return "内网IP";
|
||||
}
|
||||
|
||||
try {
|
||||
Map<String, Object> paramMap = new HashMap<>();
|
||||
paramMap.put("ip", ip);
|
||||
paramMap.put("json", true);
|
||||
String response = HttpUtil.get(ADDRESS_URL, paramMap);
|
||||
if (StringUtils.isBlank(response)) {
|
||||
log.error("根据IP获取地址异常 {}", ip);
|
||||
return UNKNOWN;
|
||||
}
|
||||
|
||||
Address address = JsonUtils.parseObject(response, Address.class);
|
||||
return String.format("%s %s", address.getPro(), address.getCity());
|
||||
} catch (Exception e) {
|
||||
log.error("根据IP获取地址异常 {}", ip);
|
||||
}
|
||||
|
||||
return UNKNOWN;
|
||||
}
|
||||
|
||||
@Data
|
||||
static class Address {
|
||||
/**
|
||||
* 省
|
||||
*/
|
||||
private String pro;
|
||||
/**
|
||||
* 市
|
||||
*/
|
||||
private String city;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,205 @@
|
|||
package net.maku.framework.common.utils;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
/**
|
||||
* IP地址 工具类
|
||||
*
|
||||
* @author 阿沐 babamu@126.com
|
||||
*/
|
||||
public class IpUtils {
|
||||
|
||||
/**
|
||||
* 获取客户端IP地址
|
||||
*/
|
||||
public static String getIpAddr(HttpServletRequest request) {
|
||||
if (request == null) {
|
||||
return "unknown";
|
||||
}
|
||||
String 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("X-Forwarded-For");
|
||||
}
|
||||
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.getHeader("X-Real-IP");
|
||||
}
|
||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
|
||||
ip = request.getRemoteAddr();
|
||||
}
|
||||
|
||||
return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : getMultistageReverseProxyIp(ip);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否为内部IP地址
|
||||
*
|
||||
* @param ip IP地址
|
||||
*/
|
||||
public static boolean internalIp(String ip) {
|
||||
byte[] addr = textToNumericFormatV4(ip);
|
||||
return internalIp(addr) || "127.0.0.1".equals(ip);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否为内部IP地址
|
||||
*
|
||||
* @param addr byte地址
|
||||
*/
|
||||
private static boolean internalIp(byte[] addr) {
|
||||
if (addr == null || addr.length < 2) {
|
||||
return true;
|
||||
}
|
||||
final byte b0 = addr[0];
|
||||
final byte b1 = addr[1];
|
||||
// 10.x.x.x/8
|
||||
final byte SECTION_1 = 0x0A;
|
||||
// 172.16.x.x/12
|
||||
final byte SECTION_2 = (byte) 0xAC;
|
||||
final byte SECTION_3 = (byte) 0x10;
|
||||
final byte SECTION_4 = (byte) 0x1F;
|
||||
// 192.168.x.x/16
|
||||
final byte SECTION_5 = (byte) 0xC0;
|
||||
final byte SECTION_6 = (byte) 0xA8;
|
||||
switch (b0) {
|
||||
case SECTION_1:
|
||||
return true;
|
||||
case SECTION_2:
|
||||
if (b1 >= SECTION_3 && b1 <= SECTION_4) {
|
||||
return true;
|
||||
}
|
||||
case SECTION_5:
|
||||
if (b1 == SECTION_6) {
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将IPv4地址转换成字节
|
||||
*
|
||||
* @param text IPv4地址
|
||||
* @return byte 字节
|
||||
*/
|
||||
public static byte[] textToNumericFormatV4(String text) {
|
||||
if (text.length() == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
byte[] bytes = new byte[4];
|
||||
String[] elements = text.split("\\.", -1);
|
||||
try {
|
||||
long l;
|
||||
int i;
|
||||
switch (elements.length) {
|
||||
case 1:
|
||||
l = Long.parseLong(elements[0]);
|
||||
if ((l < 0L) || (l > 4294967295L)) {
|
||||
return null;
|
||||
}
|
||||
bytes[0] = (byte) (int) (l >> 24 & 0xFF);
|
||||
bytes[1] = (byte) (int) ((l & 0xFFFFFF) >> 16 & 0xFF);
|
||||
bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);
|
||||
bytes[3] = (byte) (int) (l & 0xFF);
|
||||
break;
|
||||
case 2:
|
||||
l = Integer.parseInt(elements[0]);
|
||||
if ((l < 0L) || (l > 255L)) {
|
||||
return null;
|
||||
}
|
||||
bytes[0] = (byte) (int) (l & 0xFF);
|
||||
l = Integer.parseInt(elements[1]);
|
||||
if ((l < 0L) || (l > 16777215L)) {
|
||||
return null;
|
||||
}
|
||||
bytes[1] = (byte) (int) (l >> 16 & 0xFF);
|
||||
bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);
|
||||
bytes[3] = (byte) (int) (l & 0xFF);
|
||||
break;
|
||||
case 3:
|
||||
for (i = 0; i < 2; ++i) {
|
||||
l = Integer.parseInt(elements[i]);
|
||||
if ((l < 0L) || (l > 255L)) {
|
||||
return null;
|
||||
}
|
||||
bytes[i] = (byte) (int) (l & 0xFF);
|
||||
}
|
||||
l = Integer.parseInt(elements[2]);
|
||||
if ((l < 0L) || (l > 65535L)) {
|
||||
return null;
|
||||
}
|
||||
bytes[2] = (byte) (int) (l >> 8 & 0xFF);
|
||||
bytes[3] = (byte) (int) (l & 0xFF);
|
||||
break;
|
||||
case 4:
|
||||
for (i = 0; i < 4; ++i) {
|
||||
l = Integer.parseInt(elements[i]);
|
||||
if ((l < 0L) || (l > 255L)) {
|
||||
return null;
|
||||
}
|
||||
bytes[i] = (byte) (int) (l & 0xFF);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
return null;
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取本地IP地址
|
||||
*
|
||||
* @return 本地IP地址
|
||||
*/
|
||||
public static String getHostIp() {
|
||||
try {
|
||||
return InetAddress.getLocalHost().getHostAddress();
|
||||
} catch (UnknownHostException ignored) {
|
||||
|
||||
}
|
||||
return "127.0.0.1";
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取主机名
|
||||
*
|
||||
* @return 本地主机名
|
||||
*/
|
||||
public static String getHostName() {
|
||||
try {
|
||||
return InetAddress.getLocalHost().getHostName();
|
||||
} catch (UnknownHostException ignored) {
|
||||
|
||||
}
|
||||
return "未知";
|
||||
}
|
||||
|
||||
/**
|
||||
* 从反向代理中,获得第一个非 unknown IP地址
|
||||
*/
|
||||
public static String getMultistageReverseProxyIp(String ip) {
|
||||
// 反向代理检测
|
||||
if (ip.indexOf(",") > 0) {
|
||||
final String[] ips = ip.trim().split(",");
|
||||
for (String sub : ips) {
|
||||
if (!"unknown".equalsIgnoreCase(sub)) {
|
||||
ip = sub;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ip;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user