前后端实现解析用户请求ip地址

前言

在我的软件系统中,如果希望安全系数高一些的话,往往会有用户登陆行为表来记录用户登陆行为,保障用户账号安全,比如记录登陆地址,每次登陆时候读取数据最近几次登陆地点,进行账号安全验证
假如以下是我的用户登陆行为表

在这里插入图片描述

实现获取用户登陆地址的方法有很多种,比如通过前端整合第三方gps库发送地址,也可以通过整合ip地址来查询,我这里采取第二种,既然已经获取到了ip,那么就直接使用ip进行解析

前端操作

首先在前后端项目中,前端文件时是部署给nginx来完成负载均衡的,这里我们看nginx的配置文件

nginx主配置

nginx.conf

#user  nobody;
worker_processes  1;events {worker_connections  1024;
}
##nginx.conf   把里面注释的内容和静态资源配置相关删除,文件加载 http模块中有许多的server 一个server表示一个虚拟主机
http {include       mime.types;default_type  application/octet-stream;sendfile        on;keepalive_timeout  65;# 引入自定义配置文件include web.conf/*.conf;
}

这里我是将我前端的配置文件全部放在web.conf目录下的,所以主配置文件只需要负载导入

前端项目的具体

gate-way.conf (我的配置名)

upstream admin-gateway{server localhost:51603;
}server {listen 8803;location / {root html/admin-web/;index index.html;}location ~/service_6001/(.*) {proxy_pass http://admin-gateway/$1;proxy_set_header HOST $host;  # 不改变源请求头的值proxy_pass_request_body on;  #开启获取请求体proxy_pass_request_headers on;  #开启获取请求头proxy_set_header X-Real-IP $remote_addr;   # 记录真实发出请求的客户端IP 用于记录ipproxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;  #记录代理信息}
}

解析:

  • localtion模块配置前端读取的根目录
  • listen该前端的端口
  • upstream admin-gateway反向代理的具体地址
  • proxy_set_header X-Real-IP $remote_addr; 重点是这个
  • ~/service_6001/(.*) 是一个正则表达式,用于匹配以 “/service_6001/” 开头的请求路径,并捕获括号内的内容。
  • proxy_pass http://admin-gateway/$1;:

proxy_pass 用于指定被代理的服务器地址。
在这里,http://admin-gateway 是代理目标的基础地址。
$1 是正则表达式中捕获的第一个分组的变量,即括号内的内容。这是用于在代理目标中构建新的路径
比如
/service_6001/login 代理到admin-gateway就是localhost:51603/login

比如在这里插入图片描述
此时真实请求地址是 localhost:51603/admin/login/in

后端操作

这里使用ip2region , Ip2region开源项目,github地址:https://github.com/lionsoul2014/ip2region。一个离线地址库可以根据ip地址来查询文件中的地址,准确率高达99.9%,吹的话就不说了,这里可以看github查看所有优点
这里直接将整合

导入依赖
  <!-- ip2region --><dependency><groupId>org.lionsoul</groupId><artifactId>ip2region</artifactId><version>2.6.3</version></dependency><dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.6</version></dependency>

ip2region 用于 IP 地址解析,提供了高性能的 IP 地址定位功能。
commons-io 提供了一些常见的、与 I/O 操作相关的工具类,用于简化和增强 Java 的 I/O 操作。

下载离线数据集

去官网下载整个项目,需要的是解压后的data/xdb文件
在这里插入图片描述
在这里插入图片描述
然后新建ip2region目录把数据文件导入
目录结构
在这里插入图片描述

工具类
import org.apache.commons.io.FileUtils;
import org.lionsoul.ip2region.xdb.Searcher;import java.io.File;
import java.text.MessageFormat;
import java.util.Objects;public class AddressUtil {/*** 当前记录地址的本地DB*/private static final String TEMP_FILE_DIR = "/home/admin/app/";/*** 根据IP地址查询登录来源** @param ip* @return*/public static String getCityInfo(String ip) {try {// 获取当前记录地址位置的文件String dbPath = Objects.requireNonNull(AddressUtil.class.getResource("/ip2region/ip2region.xdb")).getPath();File file = new File(dbPath);//如果当前文件不存在,则从缓存中复制一份if (!file.exists()) {dbPath =    TEMP_FILE_DIR + "ip.db";System.out.println(MessageFormat.format("当前目录为:[{0}]", dbPath));file = new File(dbPath);FileUtils.copyInputStreamToFile(Objects.requireNonNull(AddressUtil.class.getClassLoader().getResourceAsStream("classpath:ip2region/ip2region.xdb")), file);}//创建查询对象Searcher searcher = Searcher.newWithFileOnly(dbPath);//开始查询return searcher.searchByStr(ip);} catch (Exception e) {e.printStackTrace();}//默认返回空字符串return "";}
//todo 测试public static void main(String[] args) {System.out.println(getCityInfo(""));}
}

测试这里ip是我的服务器
在这里插入图片描述

库有了,需要ip地址才能解析地方

获取请求ip

之前配置前端是携带真实请求地址的,那么只需要解析即可
这里我直接在controller进行解析
controller

@RestController
@RequestMapping("/login")
public class LoginController {
@Autowired
AdUserLoginService userService;@PostMapping("/in")public ResponseResult login(@RequestBody AdUserDto dto, HttpServletRequest request){String ipAddress = request.getHeader("x-forwarded-for");if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {ipAddress = request.getHeader("Proxy-Client-IP");}if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {ipAddress = request.getHeader("WL-Proxy-Client-IP");}if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {ipAddress = request.getRemoteAddr();}System.out.println("登陆用户的ip地址为"+ ipAddress);return userService.login(dto,ipAddress);}}

获取 x-forwarded-for 头部信息:
x-forwarded-for 是一个常用的 HTTP 头部字段,用于表示客户端的原始 IP 地址,如果请求经过了代理服务器,这个字段可能包含了多个 IP 地址,通过逗号分隔。所以在这里,首先尝试从这个字段中获取用户的 IP 地址。

  1. 如果 x-forwarded-for 为空或者为 “unknown”,尝试获取其他头部信息:

if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {ipAddress = request.getHeader("WL-Proxy-Client-IP");
}

如果 x-forwarded-for 为空或者为 “unknown”,则尝试从其他可能包含用户 IP 地址的头部信息中获取。这包括 Proxy-Client-IP 和 WL-Proxy-Client-IP 头部。
3.
如果上述头部信息都未获取到有效的 IP 地址,使用 request.getRemoteAddr():

if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {ipAddress = request.getRemoteAddr();
}

如果前面的头部信息都未获取到有效的 IP 地址,最后使用 request.getRemoteAddr() 获取客户端的 IP 地址。

这里的controller路径是login开头而不是admin/开头是因为我这里使用了网关转发时候省略了前缀

spring:cloud:gateway:globalcors:add-to-simple-url-handler-mapping: true # 将全局CORS配置添加到SimpleUrlHandlerMappingcorsConfigurations:'[/**]':allowedHeaders: "*" # 允许所有请求头allowedOrigins: "*" # 允许所有来源allowedMethods:- GET- POST- DELETE- PUT- OPTION# 允许的HTTP请求方法,包括OPTIONS(通常应该是OPTIONS而不是OPTION)routes:- id: adminuri: lb://adminpredicates:- Path=/admin/**filters:- StripPrefix= 1

#去掉请求路径中的一个前缀(通常是去掉服务名的前缀) filters 下的 - StripPrefix=1: 当请求匹配到这个路由规则时,会执行此处定义的过滤器。StripPrefix=1 表示去掉请求路径中的一个前缀。在这个场景下,如果请求路径是 /admin/example,经过这个过滤器后,会将 /admin 去掉,转发到后端服务的路径就变成了 /example。

好了这个不是重点,继续讲业务

测试controller是否能获取ip,测试成功在这里插入图片描述
具体实现业务的

业务代码

Service

@Service
public class AdUserLoginServiceImpl extends ServiceImpl<AdUserLoginMapper, AdUserLogin>implements AdUserLoginService {
@Autowired
AdUserMapper adUserMapper;@Overridepublic ResponseResult login(AdUserDto dto, String ipAddress) {//1.检查参数if(StringUtils.isBlank(dto.getName()) || StringUtils.isBlank(dto.getPassword())){return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID,"用户名或密码为空");}//2.查询用户AdUser user = adUserMapper.selectOne(Wrappers.<AdUser>lambdaQuery().eq(AdUser::getName, dto.getName()));if(user == null){
//            说明没有该用户return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);}//2.1.检查密码//3.比对密码String salt = user.getSalt();String pwd = dto.getPassword();
//        获取盐加密和数据库密码比较String codeepwd = DigestUtils.md5DigestAsHex((pwd + salt).getBytes());if(codeepwd.equals(user.getPassword())){//4.封装返回数据  jwtMap<String,Object> map  = new HashMap<>();map.put("token", AppJwtUtil.getToken(user.getId().longValue()));user.setSalt("");user.setPassword("");map.put("user",user);
//            写入登陆行为AdUserLogin adUserLogin = new AdUserLogin();adUserLogin.setUserId(user.getId());// 字符在字符串中的位置索引,如果字符不存在,则返回 -1。通过判断索引是否为 -1if (ipAddress.indexOf(',')!=-1){
//                一样的效果
//                ipAddress=ipAddress.split(",")[0];ipAddress = ipAddress.substring(0,ipAddress.indexOf(','));}adUserLogin.setIp(ipAddress);
//            保存用户登陆地址adUserLogin.setAddress(AddressUtil.getCityInfo(ipAddress));adUserLogin.setCreatedTime(new Date());save(adUserLogin);return ResponseResult.okResult(map);}else {return ResponseResult.errorResult(AppHttpCodeEnum.LOGIN_PASSWORD_ERROR);}}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/237554.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用pytest+selenium+allure实现web页面自动化测试

测试文件 base 基本方法data 测试数据page web页面相关操作image 测试截图log 日志文件report 测试报告文件temp 临时文件tool 文件读取&#xff0c;发邮件文件TestCases 测试用例 在page下的__init__.py文件下配置 import os import time from selenium.webdriver.common.by…

python算法例22 下一个更大的数

1. 问题描述 给定一个环形数组&#xff08;最后一个元素的下一个元素是数组的第一个元素&#xff09;&#xff0c;为每个元素打印下一个更大的元素。数字x的下一个更大的数&#xff0c;是遍历数组的过程中出现的第一个更大的数字&#xff0c;这意味着可以循环搜索以查找其下一…

伪协议和反序列化 [ZJCTF 2019]NiZhuanSiWei

打开题目 代码审计 第一层绕过 if(isset($text)&&(file_get_contents($text,r)"welcome to the zjctf")){ echo "<br><h1>".file_get_contents($text,r)."</h1></br>"; 要求我们get传参的text内容必须为w…

服务器的维护是如何操作的

服务器的维护是如何操作的 服务器可以说是不可或缺的资源&#xff0c;因为现在网络技术发达&#xff0c;我们的生活也都离不开网络的存在&#xff0c;我们想要获取的业务、资料等大多是通过网络进行&#xff0c;所以想要顺应潮流并获得发展&#xff0c;肯定需要服务器来将企业…

案例109:基于微信小程序的高校寻物平台

文末获取源码 开发语言&#xff1a;Java 框架&#xff1a;SSM JDK版本&#xff1a;JDK1.8 数据库&#xff1a;mysql 5.7 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a;Maven3.5.4 小程序框架&#xff1a;uniapp 小程序开发软件&#xff1a;HBuilder X 小程序…

【PostgreSQL】从零开始:(二十一)数据类型-布尔类型

布尔&#xff08;boolean&#xff09;类型 概述 布尔类型是一种数据类型&#xff0c;表示真&#xff08;true&#xff09;或假&#xff08;false&#xff09;的值。在计算机中&#xff0c;布尔类型主要用于判断条件的真假。布尔类型通常用于控制流程、条件判断和逻辑运算等方…

【WebRTC---源码篇】(二十五)音视频同步

RTC音视频同步场景: 音视频不在同一个时间点开始采集,如在视频先采集,音频后采集的情况下。我们不能贸然的认为音频起点来对齐视频起点,这种情况下,如何对音视频进行处理,就涉及到了音视频同步的知识。 解决思路: 通过现有条件,我们拥有RTP和SR,那么是不是可以用这两…

爬虫工作量由小到大的思维转变---<第二十章 Scrapy几个常规参数的调整策略心得>

前言: CONCURRENT_REQUESTS 32 # 设置请求并发数 DOWNLOAD_TIMEOUT 5 # 设置超时时间为5秒 RETRY_TIMES 2 # 设置你想要的重试次数 DOWNLOAD_DELAY 0.1 # 控制两个连续请求之间的延迟时间&#xff0c;设置为0.1表示每次请求之间的等待时间为0.1秒 CONCURRENT_REQUESTS_…

[XR806开发板试用] XR806——基于FreeRTOS下部署竞技机器人先进模糊控制器

前言 很荣幸参与到由“极术社区和全志在线联合组织”举办的XR806开发板试用活动。本人热衷于各种的开发板的开发&#xff0c;同时更愿意将其实现到具体项目中。秉承以上原则&#xff0c;发现大家的重心都放在开发中的环境构建过程&#xff0c;缺少了不少实际应用场景的运用&am…

【PostgreSQL】从零开始:(二十二)数据类型-枚举类型

概述 什么是枚举 枚举&#xff0c;又称为列举、举例或列举法&#xff0c;是一种通过逐一列举、点明或列举的方法来表达、阐述、说明或论述某个问题、观点或概念的过程。在数学、逻辑学和哲学中&#xff0c;枚举被用于证明、论证或说明某个命题、定理或理论的正确性或错误性。…

数据仓库-数据治理小厂实践

一、简介 数据治理贯穿数仓中数据的整个生命周期&#xff0c;从数据的产生、加载、清洗、计算&#xff0c;再到数据展示、应用&#xff0c;每个阶段都需要对数据进行治理&#xff0c;像有些比较大的企业都是有自己的数据治理平台或者会开发一些便捷的平台&#xff0c;对于没有平…

鸿蒙-HarmonyOS之初见

鸿蒙初识&#xff0c;此事能成&#xff01;&#xff01; 自己安装工具、配置环境并运行成功&#xff0c;流程记录。 一、首先官网下载开发工具 官网地址&#xff1a;https://developer.huawei.com/consumer/cn/ 当前最新的版本3.1 &#xff0c;windows和Mac&#xff0c;Mac又…

oppo 手机刷机流程

一、操作步骤&#xff1a; 一&#xff09;解锁BootLoader 以下是一种常见的方法&#xff0c;可以尝试获取OPPO手机的Root权限&#xff08;以参考信息为准&#xff0c;具体步骤可能因设备型号和系统版本而有所不同&#xff09;&#xff1a; 11). 解锁Bootloader&#xff1a;首…

【Python百宝箱】优化Python开发体验:日志记录、错误监控与高级调试

标题&#xff1a;“Python开发者的调试与性能优化大全” 前言 在软件开发的旅程中&#xff0c;调试和性能优化是每位开发者都需要掌握的关键技能。Python提供了丰富的工具和库&#xff0c;以应对开发中的各种挑战。本文将深入探讨logging、loguru、sentry、pdb、py-spy和debu…

js中的Array.from()和Array.of()方法的用法详情

&#x1f601; 作者简介&#xff1a;一名大四的学生&#xff0c;致力学习前端开发技术 ⭐️个人主页&#xff1a;夜宵饽饽的主页 ❔ 系列专栏&#xff1a;JavaScript小贴士 &#x1f450;学习格言&#xff1a;成功不是终点&#xff0c;失败也并非末日&#xff0c;最重要的是继续…

Android 12 (InputMethodManagerService) 替换默认输入法为Pinyin输入法

1.问题场景 由于系统自带的Latin输入法不支持遥控器操作&#xff0c;需要替换为RK的拼音输入法。 2. 替换步骤 1&#xff09;将LatinIME从mk中删除&#xff0c;让系统编译的时候不编译该apk --- a/Android/build/make/target/product/handheld_product.mkb/Android/build/m…

VScode安装C/C++编译器步骤

一、安装C/C插件 二、安装 MinGW-w64 工具链 使用国内源 git clone https://gitee.com/cuihongxi/ubuntu2-mac.git 下载后进入到VScode文件夹下&#xff0c;点击msys2-x86_64-20231026.exe进行安装 完成后&#xff0c;确保选中“立即运行 MSYS2”框&#xff0c;然后选择“完…

stable diffusion工作原理

目录 序言stable diffusion能做什么扩散模型正向扩散逆向扩散 如何训练逆向扩散 Stable Diffusion模型潜在扩散模型变分自动编码器图像分辨率图像放大为什么潜在空间可能存在&#xff1f;在潜在空间中的逆向扩散什么是 VAE 文件&#xff1f; 条件化(conditioning)文本条件化&am…

深信服技术认证“SCSA-S”划重点:命令执行漏洞

为帮助大家更加系统化地学习网络安全知识&#xff0c;以及更高效地通过深信服安全服务认证工程师考核&#xff0c;深信服特别推出“SCSA-S认证备考秘笈”共十期内容&#xff0c;“考试重点”内容框架&#xff0c;帮助大家快速get重点知识~ 划重点来啦 *点击图片放大展示 深信服…

前端验收测试驱动开发

我们听说过很多关于测试驱动开发&#xff08;TDD&#xff09;的内容。那么什么是ATDD&#xff1f; ATDD代表验收测试驱动开发&#xff0c;这是一种定义验收标准并创建自动化测试来验证是否满足这些标准的软件开发方法。ATDD是一种协作方法&#xff0c;涉及客户、开发人员和测试…