【Flask网站获取IIS通过URL重写进入的访问者IP】

发布于:2025-08-29 ⋅ 阅读:(18) ⋅ 点赞:(0)

【Flask网站获取IIS通过URL重写进入的访问者IP】

前言:

我在flask网站项目的登录页面中,有一个逻辑是获取访问者的IP地址,并且记录,如果访问者密码输入错误超过1小时20次,我就禁止此IP登录,可是,我把网站放在IIS上,IIS通过URL重写来进入网站,以至于我的网站后台python代码获取的IP地址是本机的IIS地址,也就是127.0.0.1,这种情况我们这样解决:

原因:

在 IIS 环境中使用 URL 重写时,Flask 获取到 127.0.0.1 是因为请求经过 IIS 转发后,原始客户端 IP 被隐藏了。要解决这个问题,需要配置 IIS 传递原始 IP 地址,并在 Flask 中正确获取。

解决办法:

配置 IIS 传递原始 IP
在 IIS 的 URL 重写规则中,确保添加了传递原始 IP 的设置,修改你的 web.config 文件

<configuration>
  <system.webServer>
    <rewrite>
      <rules>
        <rule name="ReverseProxyInboundRule1" stopProcessing="true">
          <match url="(.*)" />
          <action type="Rewrite" url="http://localhost:5000/{R:1}" />
          <!-- 添加这行传递原始IP -->
          <serverVariables>
            <set name="HTTP_X_FORWARDED_FOR" value="{REMOTE_ADDR}" />
          </serverVariables>
        </rule>
      </rules>
    </rewrite>
    <!-- 允许修改HTTP_X_FORWARDED_FOR服务器变量 -->
    <security>
      <requestFiltering>
        <serverVariables>
          <add name="HTTP_X_FORWARDED_FOR" allowDefinition="Everywhere" />
        </serverVariables>
      </requestFiltering>
    </security>
  </system.webServer>
</configuration>

然后在 Flask 中获取真实 IP:

from flask import Flask, request, render_template
import time

app = Flask(__name__)

# 存储IP地址和失败尝试的字典
failed_attempts = {}

def get_real_ip():
    """获取客户端真实IP地址"""
    # 从代理头获取IP,如果存在的话
    x_forwarded_for = request.headers.get('X-Forwarded-For')
    if x_forwarded_for:
        # X-Forwarded-For可能包含多个IP,取第一个
        return x_forwarded_for.split(',')[0].strip()
    # 否则使用默认的remote_addr
    return request.remote_addr

def is_ip_blocked(ip):
    """检查IP是否被封锁"""
    if ip not in failed_attempts:
        return False
    
    attempts = failed_attempts[ip]
    # 检查1小时内失败次数是否超过20次
    now = time.time()
    # 只保留1小时内的记录
    attempts = [t for t in attempts if now - t < 3600]
    failed_attempts[ip] = attempts
    
    return len(attempts) >= 20

@app.route('/login', methods=['GET', 'POST'])
def login():
    ip = get_real_ip()
    
    # 检查IP是否被封锁
    if is_ip_blocked(ip):
        return render_template('login.html', error='您的IP因多次登录失败已被暂时封锁')
    
    if request.method == 'POST':
        username = request.form.get('username')
        password = request.form.get('password')
        
        # 验证用户名和密码
        if not verify_credentials(username, password):
            # 记录失败尝试
            if ip not in failed_attempts:
                failed_attempts[ip] = []
            failed_attempts[ip].append(time.time())
            return render_template('login.html', error='用户名或密码错误')
        
        # 登录成功
        return redirect('/dashboard')
    
    return render_template('login.html')

def verify_credentials(username, password):
    """验证用户名和密码的函数(示例)"""
    # 实际应用中这里应该连接数据库验证
    return username == 'admin' and password == 'secret'

if __name__ == '__main__':
    app.run()

配置 Flask 信任代理,如果你的 Flask 应用位于多个代理之后,需要配置信任代理:

from werkzeug.middleware.proxy_fix import ProxyFix

# 根据实际代理层数调整参数
app.wsgi_app = ProxyFix(
    app.wsgi_app, x_for=1, x_proto=1, x_host=1, x_port=1, x_prefix=1
)

这些配置的原理是让 IIS 在转发请求时将原始客户端 IP 地址放在X-Forwarded-For头中,然后 Flask 应用从这个头中获取真实的客户端 IP 地址,而不是 IIS 服务器的地址。
完成这些配置后,你的登录限制逻辑就能基于真实的客户端 IP 地址工作了。


网站公告

今日签到

点亮在社区的每一天
去签到