springboot存储登录用户信息(springboot获取登录用户)

来源:网络技术联盟站 

链接:https://www.wljslmz.cn/19827.html

在登录模块,我们经常要记录登录日志,其中比较重要的信息有ip地址和ip归属地,像我们公司开发的产品会提供给用户试用,因为我们做的是无人机应用方向的,即使试用也会产生费用,因为我们很多功能一旦用了就会消耗我们大量的资源,所以为了防止客户在试用时恶意传播账号,我们必须要记录用户的登录ip以及归属地,一旦遇到恶意传播的,轻则通知,重则警告,甚至不予试用,终止合作。

本文我将从我们的系统中划分出来一个简单的小功能:登录日志。

让我们直接开始!

一、说在前面

因为本身系统很庞大,加上代码的隐私性,我这边不会介绍非常多的属性,不过我能保证的是,代码你抄上去肯定能用。

二、数据库设计

按照开发流程,首先肯定是数据库的设计,我这边直接给出数据库建表语句:

CREATE TABLE `login_log` (
  `id` int NOT NULL AUTO_INCREMENT COMMENT \\\'主键\\\',
  `name` varchar(255) DEFAULT NULL COMMENT \\\'登陆人姓名\\\',
  `ip` varchar(255) DEFAULT NULL COMMENT \\\'登录ip\\\',
  `ip_attribution` varchar(255) DEFAULT NULL COMMENT \\\'ip归属地信息\\\',
  `create_time` datetime DEFAULT NULL COMMENT \\\'创建时间\\\',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

在建表前,请保证你的数据库是创建好的,这个前提有点搞笑了。

由表可以看到,我们创建了login_log表,即登录日志表,字段名有id(主键)、name(登陆人姓名)、ip(登录ip)、ip_attribution(ip归属地信息)、create_time(创建时间)。

在真实的企业环境中,登录日志肯定远远不止这些,我是从我们的表中挑出了最基本的字段,像ip所属经纬度,因为需要调用第三方服务,我这边没有展示,当然市面上也有开源的根据ip获取经纬度的库,只不过不准确,想要准确还是要购买第三方服务。

三、代码编写

3.1 框架选型

我选用的框架是:

  • SpringBoot:2.7.0
  • jdk:1.8
  • mybatis-plus:3.4.2
  • lombok:1.18.22

还有其他基础的到时候报红的时候自行解决。

3.2 pom 依赖

跟ip归属地相关的依赖:

<dependency>
  <groupId>org.lionsoul</groupId>
  <artifactId>ip2region</artifactId>
  <version>1.7.2</version>
</dependency>

跟加载ip归属地数据库文件的依赖:

<dependency>
  <groupId>commons-io</groupId>
  <artifactId>commons-io</artifactId>
  <version>2.5</version>
</dependency>

3.3 实体类

LoginLogEntity:

package com.wljlsmz.transitcenter.model.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;

import java.time.LocalDateTime;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author: wljlsmz
 * @date: 2022/11/15 10:28
 * @description: 用户登录日志实体类
 */
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@TableName(\\\"login_log\\\")
public class LoginLogEntity {

    /**
     * 主键
     */
    @TableId(type = IdType.AUTO)
    private Integer id;

    /**
     * 登陆人姓名
     */
    @TableField(\\\"name\\\")
    private String name;

    /**
     * 登录ip
     */
    @TableField(\\\"ip\\\")
    private String ip;

    /**
     * ip归属地信息
     */
    @TableField(\\\"ip_attribution\\\")
    private String ipAttribution;

    /**
     * 创建时间
     */
    @TableField(\\\"create_time\\\")
    private LocalDateTime createTime;
}

3.4 Mapper类

LoginLogMapper:

package com.wljlsmz.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.wljlsmz.transitcenter.model.entity.LoginLogEntity;

/**
 * @author: wljlsmz
 * @date: 2022/11/15 10:28
 * @description: 登录日志mapper接口类
 */
public interface LoginLogMapper extends BaseMapper<LoginLogEntity> {
}

3.5 service类

ILoginLogService:

package com.wljlsmz.transitcenter.service;

import com.wljlsmz.transitcenter.model.dto.LoginLogDTO;

/**
 * @author: wljlsmz
 * @date: 2022/11/15 10:28
 * @description: 登录日志服务接口类
 */
public interface ILoginLogService {

    int saveLoginLog(LoginLogDTO loginLogDTO);
}

LoginLogServiceImpl:

package com.wljlsmz.transitcenter.service.impl;

import com.wljlsmz.transitcenter.mapper.LoginLogMapper;
import com.wljlsmz.transitcenter.model.dto.LoginLogDTO;
import com.wljlsmz.transitcenter.model.entity.LoginLogEntity;
import com.wljlsmz.transitcenter.service.ILoginLogService;
import com.wljlsmz.transitcenter.util.CopyUtil;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;

/**
 * @author: wljlsmz
 * @date: 2022/11/15 10:28
 * @description: 登录日志服务接口实现类
 */
@Service
public class LoginLogServiceImpl implements ILoginLogService {

    @Autowired
    private LoginLogMapper mapper;

    @Override
    public int saveLoginLog(LoginLogDTO loginLogDTO) {
        LoginLogEntity loginLogEntity = CopyUtil.copy(loginLogDTO, LoginLogEntity.class);
        loginLogEntity.setCreateTime(LocalDateTime.now());
        return mapper.insert(loginLogEntity);
    }
}

3.6 IP工具类

IpUtils:

package com.wljlsmz.transitcenter.util;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.lionsoul.ip2region.DataBlock;
import org.lionsoul.ip2region.DbConfig;
import org.lionsoul.ip2region.DbSearcher;
import org.lionsoul.ip2region.Util;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import java.io.File;
import java.io.InputStream;

import javax.servlet.http.HttpServletRequest;

import lombok.extern.slf4j.Slf4j;


/**
 * @author: wljlsmz
 * @date: 2022/11/15 10:28
 * @description: ip工具类
 */
@Slf4j
public class IpUtils {

    /**
     * 本地环回地址
     */
    private static final String LOCAL_IP = \\\"127.0.0.1\\\";

    /**
     * 未知
     */
    private static final String UNKNOWN = \\\"unknown\\\";

    public static String getIpAddr(HttpServletRequest request) {

        if (request == null) {
            return UNKNOWN;
        }

        String ip = request.getHeader(\\\"x-forwarded-for\\\");
        if (StringUtils.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader(\\\"Proxy-Client-IP\\\");
        }
        if (StringUtils.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader(\\\"X-Forwarded-For\\\");
        }
        if (StringUtils.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader(\\\"WL-Proxy-Client-IP\\\");
        }
        if (StringUtils.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader(\\\"X-Real-IP\\\");
        }

        if (StringUtils.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }

        return \\\"0:0:0:0:0:0:0:1\\\".equals(ip) ? LOCAL_IP : ip;
    }

    public static String getCityInfo(String ip) throws Exception {

        if (!Util.isIpAddress(ip)) {
            log.error(\\\"错误: 无效的ip地址\\\");
            return null;
        }

        InputStream is = new PathMatchingResourcePatternResolver().getResources(\\\"ip2region.db\\\")[0].getInputStream();
        File target = new File(\\\"ip2region.db\\\");
        FileUtils.copyInputStreamToFile(is, target);
        is.close();

        if (StringUtils.isEmpty(String.valueOf(target))) {
            log.error(\\\"错误: 无效的ip2region.db文件\\\");
            return null;
        }

        DbSearcher searcher = new DbSearcher(new DbConfig(), String.valueOf(target));

        try {
            DataBlock dataBlock = (DataBlock) searcher.getClass().getMethod(\\\"btreeSearch\\\", String.class).invoke(searcher, ip);

            String ipInfo = dataBlock.getRegion();
            if (!StringUtils.isEmpty(ipInfo)) {
                ipInfo = ipInfo.replace(\\\"|0\\\", \\\"\\\");
                ipInfo = ipInfo.replace(\\\"0|\\\", \\\"\\\");
            }

            return ipInfo;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

上诉代码中提到了ip2region.db文件,这个文件需要放到resources目录下:

springboot存储登录用户信息(springboot获取登录用户)

ip2region.db文件我放在网盘中,大家可以按需下载:

链接:https://pan.quark.cn/s/a5e187b7a91b
提取码:pjqQ

点击下载即可:

springboot存储登录用户信息(springboot获取登录用户)

3.7 Controller类

这个类就使用到了以上所有的准备代码:

UserController:

package com.wljlsmz.transitcenter.controller;

import com.wljlsmz.transitcenter.common.response.ResponseResult;
import com.wljlsmz.transitcenter.model.dto.LoginDTO;
import com.wljlsmz.transitcenter.model.dto.LoginLogDTO;
import com.wljlsmz.transitcenter.service.ILoginLogService;
import com.wljlsmz.transitcenter.service.IUserService;
import com.wljlsmz.transitcenter.util.IpUtils;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;

import lombok.extern.slf4j.Slf4j;

/**
 * @author: wljlsmz
 * @date: 2022/11/15 10:28
 * @description: 用户接口类
 */
@RestController
@Slf4j
@Api(tags = \\\"用户接口\\\")
@RequestMapping(\\\"${url.user.prefix}${url.user.version}\\\")
public class UserController {

    @Autowired
    private IUserService userService;

    @Autowired
    private ILoginLogService loginLogService;

    @ApiOperation(\\\"登录\\\")
    @PostMapping(\\\"login\\\")
    public ResponseResult login(@ApiParam @RequestBody LoginDTO loginDTO, HttpServletRequest request) {

        String ip = IpUtils.getIpAddr(request);
        String cityInfo = null;
        try {
            cityInfo = IpUtils.getCityInfo(ip);
        } catch (Exception e) {
            log.error(\\\"获取ip归属地信息失败!\\\");
        }

        loginLogService.saveLoginLog(
                LoginLogDTO.builder()
                        .ip(ip)
                        .ipAttribution(cityInfo)
                        .name(loginDTO.getUserName())
                        .build());

        return userService.login(loginDTO);
    }
}

以上代码被我删减了好多,其实大家在使用的时候,值需要把下面这段代码摘出来放到自己的测试代码中即可:

String ip = IpUtils.getIpAddr(request);
String cityInfo = null;
try {
    cityInfo = IpUtils.getCityInfo(ip);
} catch (Exception e) {
    log.error(\\\"获取ip归属地信息失败!\\\");
}

loginLogService.saveLoginLog(
        LoginLogDTO.builder()
                .ip(ip)
                .ipAttribution(cityInfo)
                .name(loginDTO.getUserName())
                .build());

测试代码

我们用swagger测试一下接口:

springboot存储登录用户信息(springboot获取登录用户)

测试成功后,我们看下数据库:

springboot存储登录用户信息(springboot获取登录用户)

成功记录了ip信息,在真实的企业环境中,你也再增加一些字段。

至此代码全部演示完毕。

总结

本文主要介绍了如何在登录接口增加登录日志的记录,文中的代码大家可以参考,有任何问题可以在下方评论区与我讨论,最后感谢您的阅读,您的点赞和转发就是我不断创作的动力!


springboot存储登录用户信息(springboot获取登录用户)

原创文章,作者:网络技术联盟站,如若转载,请注明出处:https://www.sudun.com/ask/34751.html

(0)
网络技术联盟站's avatar网络技术联盟站
上一篇 2024年4月17日 下午2:48
下一篇 2024年4月17日 下午2:50

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注