Nginx请求参数解析
作者:mmseoamin日期:2023-12-21

Nginx请求参数解析,在这里插入图片描述,第1张

例: $arg_token 取的就是 uri?args 中 token=xxx 的部分

$arg_PARAMETER #这个变量包含GET请求中,如果有变量PARAMETER时的值。
$args #这个变量等于请求行中(GET请求)的参数,例如foo=123&bar=blahblah;
$binary_remote_addr #二进制的客户地址。
$body_bytes_sent #响应时送出的body字节数数量。即使连接中断,这个数据也是精确的。
$content_length #请求头中的Content-length字段。
$content_type #请求头中的Content-Type字段。
$cookie_COOKIE #cookie COOKIE变量的值
$document_root #当前请求在root指令中指定的值。
$document_uri #与$uri相同。
$host #请求主机头字段,否则为服务器名称。
$hostname #Set to the machine’s hostname as returned by gethostname
$http_HEADER
$is_args #如果有$args参数,这个变量等于”?”,否则等于”",空值。
$http_user_agent #客户端agent信息
$http_cookie #客户端cookie信息
$limit_rate #这个变量可以限制连接速率。
$query_string #与$args相同。
$request_body_file #客户端请求主体信息的临时文件名。
$request_method #客户端请求的动作,通常为GET或POST。
$remote_addr #客户端的IP地址。
$remote_port #客户端的端口。
$remote_user #已经经过Auth Basic Module验证的用户名。
$request_completion #如果请求结束,设置为OK. 当请求未结束或如果该请求不是请求链串的最后一个时,为空(Empty)。
$request_method #GET或POST
$request_filename #当前请求的文件路径,由root或alias指令与URI请求生成。
$request_uri #包含请求参数的原始URI,不包含主机名,如:”/foo/bar.php?arg=baz”。不能修改。
$scheme #HTTP方法(如http,https)。
$server_protocol #请求使用的协议,通常是HTTP/1.0或HTTP/1.1。
$server_addr #服务器地址,在完成一次系统调用后可以确定这个值。
$server_name #服务器名称:域名或IP 那部分。     // 例: set $auth_request_uri "http://$server_name:8090/system/user/auth?$args";
$server_port #请求到达服务器的端口号。
$uri #不带请求参数的当前URI,$uri不包含主机名,如”/foo/bar.html”。该值有可能和$request_uri 不一致。$request_uri是浏览器发过来的值。该值是rewrite后的值。例如做了internal redirects后。

使用auth_request做权限控制

背景:生产环境对于图片使用 标签来显示图片,或使用 element-ui 的 标签进行图片预览;

但是直接访问 url: http://192.168.0.225:8002/file/20231011/%E7%B3%BB%E7%BB%9F%E7%AE%A1%E7%90%86%E5%B7%A5%E4%BD%9C%E7%AB%99_531011143641805.pdf

浏览器会下载文件

或 直接

所有人在外网都可以访问,不安全。不会经过java 后端接口的 @SaCheckLogin 鉴权。

所以,要么不直接访问 ,而是通过后端接口返回。 要么在nginx 层加一个权限校验, lua 鉴权或 通过 nginx 自带的模块 --with-http_auth_request_module

为了省事,采用了 nginx的 模块方式:

所以,前端开发人员就需要在图片加载过程中携带验证的信息。如 token,用于身份验证、权限控制等方面。通过在图片的 URL 后面(get请求方式),或请求头中携带 token 信息,从而实现图片信息的安全传输。

同时 后端增加一个单纯的鉴权接口:

/system/user/auth

    @SaCheckLogin
    @GetMapping("/auth")
    public String info() throws Exception {
        try {
            return LoginHelper.getUsername();
        }catch (Exception e){
            throw new Exception("用户未登录!"+e.getMessage());
        }
    }

浏览器访问图片链接,然后根据request中的token信息判断此用户是否登录态 若是则返回 response.setStatus(200)

若不是登录态,则400.

技术:采用Nginx自带的auth_request模块(网上也有一些其他的方法比如安装redis模块,在nginx里直接查询redis,这里我们不做介绍)。

开启auth_request

需要重新编译nginx源码,把auth_request加入到nginx中,(1.5.4以上,默认包含auth_request,需要编译的时候开启)

配置校验参数

log_format  pro '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                              '"$http_referer" "$http_user_agent" $request_time req_body:"$request_body"'
                      '"$http_user_agent" "$http_x_forwarded_for"';
server {
    listen 8002;
    server_name 192.168.0.225 localhost api.ltkj.com;
    # root /data/wwwroot/static.ltkj.com/project;
    # 重定向到error401 时用
    proxy_intercept_errors on;
    #禁止访问的文件或目录
    location ~ ^/(\.user.ini|\.htaccess|\.git|\.svn|\.project|LICENSE|README.md)
    {
        return 404;
    }
  // 处理文件
    location ^~ /file/ {
        # expires      30d;
        set $auth_request_uri "http://$server_name:8090/system/user/auth?$args";
        auth_request /auth;
        auth_request_set $user $upstream_http_x_forwarded_user;
        proxy_set_header X-Forwarded-User $user;
        error_page 401 500 = /error401;
        root /data/wwwroot/static.ltkj.com/project;
    }
// 处理图片
    location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ {
                                # img 标签 header中设置 token方式 未成功,待测试
                                add_header Access-Control-Allow-Origin *;
                                add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
                                add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
         auth_request /auth;
         error_page 401 500 = /error401;
         auth_request_set $user $upstream_http_x_forwarded_user;
         proxy_set_header X-Forwarded-User $user;
         set $auth_request_uri "http://$server_name:8090/system/user/auth?$args";
         root /data/wwwroot/static.ltkj.com/project;
    }
    location /auth {
        # 表示该路径仅仅为nginx内部访问,一旦出了这个配置文件,则失效
        internal;
        # 自己系统的认证路径
        # proxy_pass http://localhost:8090/system/user/auth;
        proxy_pass $auth_request_uri ;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Original-URI $request_uri;
        proxy_set_header X-Original-METHOD $request_method;
        error_page 401 500  = /error401;
    }
        # 认证失败后的处理
    location = /error401 {
        # 强制浏览器不使用缓存,防止缓存带来的还能访问系统
        # 如果认证失败,跳转到自己系统的登录页面
        return 302 http://192.168.0.225:8001/index;
    }
    access_log  /data/logs/nginx/project_manager/access.log pro;
    error_log  /data/logs/nginx/project_manager/error.log ;
}

灵魂代码!灵魂代码!灵魂代码!

set $auth_request_uri "http://192.168.0.225:8090/system/user/auth?$args";

我的项目需求是对图片做权限校验,图片展示是直接在img标签里面展示的,因此,没法做请求头的设置,需要在链接后面携带校验信息。如:http://127.0.0.1/api/image/123.jpg?token=xxx

这时候校验信息,而网上大部分是没有这段代码的set $auth_request_uri "http://192.168.40.14:8080/image/auth?$query_string"; 导致参数无法传递到r后端校验地址(如果是设置请求头里的,可以获取到)。

校验成功就将127.0.0.1/api/image/123.jpg?token=xxx转发到 minio地址:9000/123.jpg。

校验失败后台设置响应状态401或403,将转发到authError.png这张图片上。

测试url

  • http://192.168.0.225:8002/pic/20230825/530825093805902100.jpg 跳转到登录页 or 首页
  • http://192.168.0.225:8002/pic/20230825/530825093805902100.jpg?Authorization=Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpblR5cGUiOiJsb2dpbiIsImxvZ2luSWQiOiJzeXNfdXNlcjoxIiwicm5TdHIiOiJ0dEtOdkE5VTNwQkllWmgxV1h5OUZETWVoUzZINk5MbCIsInVzZXJJZCI6MX0.6_FQyAqTrRsWR4HdhD2qmFeqAOrHJ6cVguCzaW2JlC0 成功预览
  • http://192.168.0.225:8002/file/20231011/系统管理工作站_531011143641805.pdf
  • http://192.168.0.225:8002/file/20231011/系统管理工作站_531011143641805.pdf?Authorization=Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpblR5cGUiOiJsb2dpbiIsImxvZ2luSWQiOiJzeXNfdXNlcjoxIiwicm5TdHIiOiJ0dEtOdkE5VTNwQkllWmgxV1h5OUZETWVoUzZINk5MbCIsInVzZXJJZCI6MX0.6_FQyAqTrRsWR4HdhD2qmFeqAOrHJ6cVguCzaW2JlC0

    ————————————————

    上面是把token加在url 后面 ?token=“xxx” ,这种方式 get方式。

    下面 尝试入到 header中

    探索前端图片如何携带token进行验证

    vue中给img的src添加token