From 9e515b1d620f5e666084b642ec7e7cf4b5f58d6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=98=BF=E6=B2=90?= Date: Sun, 28 Aug 2022 00:02:00 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E7=99=BB=E5=BD=95=E6=97=A5?= =?UTF-8?q?=E5=BF=97=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- db/dm8/fast-boot.sql | 69 +++---- db/mysql/fast-boot.sql | 41 ++--- .../system/controller/SysLogLoginController.java | 39 ++++ .../maku/system/convert/SysLogLoginConvert.java | 25 +++ .../java/net/maku/system/dao/SysLogLoginDao.java | 15 ++ .../net/maku/system/entity/SysLogLoginEntity.java | 61 ++++++ .../net/maku/system/enums/LoginOperationEnum.java | 32 ++++ .../net/maku/system/query/SysLogLoginQuery.java | 26 +++ .../maku/system/service/SysLogLoginService.java | 26 +++ .../service/impl/SysLogLoginServiceImpl.java | 69 +++++++ .../java/net/maku/system/vo/SysLogLoginVO.java | 46 +++++ .../src/main/resources/mapper/SysLogLoginDao.xml | 6 + .../maku/framework/common/utils/AddressUtils.java | 58 ++++++ .../net/maku/framework/common/utils/IpUtils.java | 205 +++++++++++++++++++++ 14 files changed, 648 insertions(+), 70 deletions(-) create mode 100644 fast-boot-system/src/main/java/net/maku/system/controller/SysLogLoginController.java create mode 100644 fast-boot-system/src/main/java/net/maku/system/convert/SysLogLoginConvert.java create mode 100644 fast-boot-system/src/main/java/net/maku/system/dao/SysLogLoginDao.java create mode 100644 fast-boot-system/src/main/java/net/maku/system/entity/SysLogLoginEntity.java create mode 100644 fast-boot-system/src/main/java/net/maku/system/enums/LoginOperationEnum.java create mode 100644 fast-boot-system/src/main/java/net/maku/system/query/SysLogLoginQuery.java create mode 100644 fast-boot-system/src/main/java/net/maku/system/service/SysLogLoginService.java create mode 100644 fast-boot-system/src/main/java/net/maku/system/service/impl/SysLogLoginServiceImpl.java create mode 100644 fast-boot-system/src/main/java/net/maku/system/vo/SysLogLoginVO.java create mode 100644 fast-boot-system/src/main/resources/mapper/SysLogLoginDao.xml create mode 100644 fast-framework/src/main/java/net/maku/framework/common/utils/AddressUtils.java create mode 100644 fast-framework/src/main/java/net/maku/framework/common/utils/IpUtils.java diff --git a/db/dm8/fast-boot.sql b/db/dm8/fast-boot.sql index 996ccc6..18ec0f7 100644 --- a/db/dm8/fast-boot.sql +++ b/db/dm8/fast-boot.sql @@ -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()); diff --git a/db/mysql/fast-boot.sql b/db/mysql/fast-boot.sql index 9f8e4da..0f64fda 100644 --- a/db/mysql/fast-boot.sql +++ b/db/mysql/fast-boot.sql @@ -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()); diff --git a/fast-boot-system/src/main/java/net/maku/system/controller/SysLogLoginController.java b/fast-boot-system/src/main/java/net/maku/system/controller/SysLogLoginController.java new file mode 100644 index 0000000..5a848c9 --- /dev/null +++ b/fast-boot-system/src/main/java/net/maku/system/controller/SysLogLoginController.java @@ -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> page(@Valid SysLogLoginQuery query) { + PageResult page = sysLogLoginService.page(query); + + return Result.ok(page); + } + +} \ No newline at end of file diff --git a/fast-boot-system/src/main/java/net/maku/system/convert/SysLogLoginConvert.java b/fast-boot-system/src/main/java/net/maku/system/convert/SysLogLoginConvert.java new file mode 100644 index 0000000..522e00a --- /dev/null +++ b/fast-boot-system/src/main/java/net/maku/system/convert/SysLogLoginConvert.java @@ -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 convertList(List list); + +} \ No newline at end of file diff --git a/fast-boot-system/src/main/java/net/maku/system/dao/SysLogLoginDao.java b/fast-boot-system/src/main/java/net/maku/system/dao/SysLogLoginDao.java new file mode 100644 index 0000000..688d9ab --- /dev/null +++ b/fast-boot-system/src/main/java/net/maku/system/dao/SysLogLoginDao.java @@ -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 { + +} \ No newline at end of file diff --git a/fast-boot-system/src/main/java/net/maku/system/entity/SysLogLoginEntity.java b/fast-boot-system/src/main/java/net/maku/system/entity/SysLogLoginEntity.java new file mode 100644 index 0000000..36e28ef --- /dev/null +++ b/fast-boot-system/src/main/java/net/maku/system/entity/SysLogLoginEntity.java @@ -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; + +} \ No newline at end of file diff --git a/fast-boot-system/src/main/java/net/maku/system/enums/LoginOperationEnum.java b/fast-boot-system/src/main/java/net/maku/system/enums/LoginOperationEnum.java new file mode 100644 index 0000000..8dba9c6 --- /dev/null +++ b/fast-boot-system/src/main/java/net/maku/system/enums/LoginOperationEnum.java @@ -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; +} diff --git a/fast-boot-system/src/main/java/net/maku/system/query/SysLogLoginQuery.java b/fast-boot-system/src/main/java/net/maku/system/query/SysLogLoginQuery.java new file mode 100644 index 0000000..78ca197 --- /dev/null +++ b/fast-boot-system/src/main/java/net/maku/system/query/SysLogLoginQuery.java @@ -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; + +} \ No newline at end of file diff --git a/fast-boot-system/src/main/java/net/maku/system/service/SysLogLoginService.java b/fast-boot-system/src/main/java/net/maku/system/service/SysLogLoginService.java new file mode 100644 index 0000000..ffb8233 --- /dev/null +++ b/fast-boot-system/src/main/java/net/maku/system/service/SysLogLoginService.java @@ -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 { + + PageResult page(SysLogLoginQuery query); + + /** + * 保存登录日志 + * + * @param username 用户名 + * @param status 登录状态 + * @param operation 操作信息 + */ + void save(String username, Integer status, Integer operation); +} \ No newline at end of file diff --git a/fast-boot-system/src/main/java/net/maku/system/service/impl/SysLogLoginServiceImpl.java b/fast-boot-system/src/main/java/net/maku/system/service/impl/SysLogLoginServiceImpl.java new file mode 100644 index 0000000..d035182 --- /dev/null +++ b/fast-boot-system/src/main/java/net/maku/system/service/impl/SysLogLoginServiceImpl.java @@ -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 implements SysLogLoginService { + + @Override + public PageResult page(SysLogLoginQuery query) { + IPage page = baseMapper.selectPage(getPage(query), getWrapper(query)); + + return new PageResult<>(SysLogLoginConvert.INSTANCE.convertList(page.getRecords()), page.getTotal()); + } + + private LambdaQueryWrapper getWrapper(SysLogLoginQuery query) { + LambdaQueryWrapper 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); + } + +} \ No newline at end of file diff --git a/fast-boot-system/src/main/java/net/maku/system/vo/SysLogLoginVO.java b/fast-boot-system/src/main/java/net/maku/system/vo/SysLogLoginVO.java new file mode 100644 index 0000000..85fd594 --- /dev/null +++ b/fast-boot-system/src/main/java/net/maku/system/vo/SysLogLoginVO.java @@ -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; + +} \ No newline at end of file diff --git a/fast-boot-system/src/main/resources/mapper/SysLogLoginDao.xml b/fast-boot-system/src/main/resources/mapper/SysLogLoginDao.xml new file mode 100644 index 0000000..be6f752 --- /dev/null +++ b/fast-boot-system/src/main/resources/mapper/SysLogLoginDao.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/fast-framework/src/main/java/net/maku/framework/common/utils/AddressUtils.java b/fast-framework/src/main/java/net/maku/framework/common/utils/AddressUtils.java new file mode 100644 index 0000000..e45d1bf --- /dev/null +++ b/fast-framework/src/main/java/net/maku/framework/common/utils/AddressUtils.java @@ -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 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; + } +} diff --git a/fast-framework/src/main/java/net/maku/framework/common/utils/IpUtils.java b/fast-framework/src/main/java/net/maku/framework/common/utils/IpUtils.java new file mode 100644 index 0000000..1652cef --- /dev/null +++ b/fast-framework/src/main/java/net/maku/framework/common/utils/IpUtils.java @@ -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; + } +}