获取客户端的访问记录(待验证)

参考:https://cloud.tencent.com/developer/article/2233415 如何在SpringBoot项目中,实现记录用户登录的IP地址及归属地信息?
https://blog.csdn.net/a254124185/article/details/117294692 微服务获取真实请求的IP

(1)springboot获取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;

选用框架
SpringBoot:2.7.0
jdk:1.8
mybatis-plus:3.4.2
lombok:1.18.22
1.1依赖

#跟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>

1.2实体类

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;
}

Mapper类

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> {
}

service类

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);
}
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);
    }
}

ip工具类

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目录下
image
链接:https://pan.baidu.com/s/1KizC6hftNlC7STjSzPYUlA
提取码:0aqk
controller类

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);
    }
}

2.微服务获取ip地址

image
2.1nginx

http {
	include mime.types; 
	default_type application/octet-stream; 

	upstream gwadds { 
		server 127.0.0.1:81; 
	}
server { 
	listen 80; 
	server_name gw.com; 
	location / { 
		proxy_pass http://gwadds/; 
		#重构请求头,获取客户端请求的IP地址 
		proxy_set_header Host $host; 
		proxy_set_header X-Real-IP $remote_addr; 
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
	} 
}

2.2网管过滤器中获取

@Component
public class GatewayFilter implements GlobalFilter {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { // nginx 会从请求头中设置 客户端的真实ip放入网关 
        String sourceIp = exchange.getRequest().getHeaders().getFirst("X-Real-IP");
        if (StringUtils.isEmpty(sourceIp)) {
            ServerHttpResponse response = exchange.getResponse();
            response.setStatusCode(HttpStatus.BAD_REQUEST);
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("code", "500");
            jsonObject.put("msg", "sourceIp is null");
            DataBuffer buffer = response.bufferFactory().wrap(jsonObject.toJSONString().getByt es());
            return response.writeWith(Mono.just(buffer));
        }// 使用网关过滤 
        return chain.filter(exchange);
    }
}

2.3微服务中获取

@RestController
@RequestMapping("/member")
public class MemberController {
    @PostMapping("/login")
    BaseResponse<JSONObject> login(@RequestBody UserLoginDto userLoginDto, 
                                   @RequestHeader("X-Real-IP") String sourceIp, 
                                   @RequestHeader("channel") String channel, 
                                   @RequestHeader("deviceInfor") String deviceInfor);
}
posted @ 2023-07-21 15:58  spiderMan1-1  阅读(36)  评论(0编辑  收藏  举报