Skip to content

异地登录提醒怎么做?给账号安全加一道锁

"您的账号在异地登录"——这种提醒大家应该都收到过。作为一个开发,你可能也想过给自己产品做一套。这篇文章讲讲怎么用IP归属地实现"异地登录提醒",以及最容易做砸的几个地方。

原理一句话

用户登录时,记录IP归属地(省份/城市)。下次登录如果"变化异常",就发提醒或者要求二次验证。就这么简单。

基础版:登录时记录位置

python
def on_login(user_id, ip):
    info = query_ip(ip)   # 查IP9
    location = None
    if info:
        location = f"{info.get('prov')} {info.get('city')}"
    # 存到用户表
    save_login_location(user_id, location, ip, time.now())

判断"异地":三个层次

层次1:按城市判断(最粗糙)

python
def check(user_id, ip):
    info = query_ip(ip)
    new_loc = f"{info.get('prov')} {info.get('city')}"
    old_loc = get_last_location(user_id)
    return new_loc != old_loc

这个方案会误报炸。原因:用户出差、搬家、甚至IP抖动,都会触发。我第一版就是这么做的,结果被用户投诉"天天提醒异地登录"。

层次2:常用IP池 + 时间窗口

改进:维护每个用户的"常用IP池",只有"新IP + 新地区 + 短时间内异常"才告警。

python
from collections import deque

def is_risky(user_id, ip, info):
    pool = get_ip_pool(user_id)   # 该用户常用的IP集合
    if ip in pool:
        return False              # 常用IP,安全
    # 不常用IP,再看地区
    new_city = f"{info.get('prov')} {info.get('city')}"
    if new_city in get_common_cities(user_id):
        return False              # 地区常去,不告警
    # 从来没去过的地区 + 不常用IP -> 风险
    return True

要点:把"常用"记成池子,别用"上一次"做唯一参照。这样用户出差去常去的地方,就不会乱弹。

层次3:结合频率和时段

更精细的:同一IP 10分钟内换了N个账号登录,或凌晨异地登录,加权重。这些组合起来,告警准确率高很多。

告警之后做什么

别只弹个提醒就完事,要给用户选择:

  • 低风险:站内提醒"您的账号近期在XX登录过";
  • 中风险:要求短信/邮箱验证码;
  • 高风险:直接冻结异常会话,要求改密码。

最容易踩的坑

1. 移动用户被天天误伤。 手机流量IP飘得厉害,真正常用户也会被判定"异地"。对策是:对移动网络用户放宽标准,或者干脆只对"IP类型异常"才告警(比如平时都是ISP家庭宽带,突然从IDC机房登录)。

2. 忽略代理。 攻击者用代理,IP常变。这种单靠地区判断没用,要结合设备指纹。IP只是第一道防线,别指望它全挡住。

3. 只记"上一次"。 记住,用常用池,别用上一次。

代码骨架

python
def login_security_check(user_id, ip):
    info = query_ip(ip)
    if not info:
        return "allow"           # 查不到,放行(或走其他验证)
    if is_risky(user_id, ip, info):
        return "verify"          # 要求二次验证
    update_ip_pool(user_id, ip)  # 记入常用池
    return "allow"

一句忠告

异地登录提醒这个功能,宁可不弹,也不要乱弹。弹多了,用户会关闭通知,甚至觉得产品有问题。把误报率压下去,比什么都重要。

接口文档:https://www.ip9.com.cn