歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> Nginx模塊系列之認證請求

Nginx模塊系列之認證請求

日期:2017/2/27 15:49:23   编辑:Linux教程
這是一個可以讓nginx的請求具備認證功能的模塊。它可以做很多極具創造力的功能,這可能是我最推薦的一個模塊。現在它已經是nginx內置的模塊,只是默認是未開啟的。曾經它也是第三方模塊,其作者現在是nginx源碼維護者之一。有著如此淵源和優秀使其被nginx收錄,自然是情理之中。

在我們經歷過的項目中,用戶登陸認證是個非常常見的功能點。我們可能有很多的子項目,這些子項目有著共同的功能,
那就是都需要經過登陸認證後才能訪問。作為有經驗的你,希望把它獨立出來。可能你已經抽象出健壯的庫,讓每個子系統直接調用它。當然這是很好的方案,但我們想讓開發人員的日子更舒服些,他們不用關心是否有認證,甚至在代碼中看不到任何認證的影子,架構師就已經神奇的幫他們搞定了這塊。


1、先來看如何實現它
./configure --with-http_auth_request_module
make && make install

server {
    listen       80;

    root   html;

    location / {
        index  index.html index.php;
    }

    #這個將在下面中被使用
    location /auth {
        proxy_pass  http://xx.xx.xx.xx; #你可以用proxy_pass
        #return 200;#可以直接讓它通過
        #其它也可以,只要讓這個location正常使用。
    }

    location ~ \.php$ {
        auth_request   /auth; #這裡將使專有php具備認證功能
        fastcgi_pass   127.0.0.1:9000;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        include        fastcgi_params;
    }
}


你要做的就是提供個 http://xx.xx.xx.xx 接口。
200:認證成功

403:認證失敗
401:很特殊
xxx:其它有問題

2、讓你成為專家
如果僅僅這樣,當然不足以把它稱為創造力。我們將看它的實現,這樣你可以做更多有想法的事。我在nginx的源碼分析系列裡提過,nginx有個神奇的機制叫子請求(subrequest)。故名思義,子請求是從請求裡發出的內部請求,至於這個內部請求是處理簡單的路徑,比如/test.html,還是具備遠程處理能力/test.php,完全由你決定,而且它永遠不會阻塞,這是非常重要的,這也是我們用接口的方式獨立出認證功能的優勢,相比代碼的阻塞,它在高並發下效果更好。

現在開始分析它的實現:src/http/modules/ngx_http_auth_request_module.c

a、先看指令,只有兩個
"auth_request" => ngx_http_auth_request(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
arcf->uri = value[1]; 這裡有個細節,這樣的實現使其不能使用變量。我已經有個具備變量的代碼。
}

"auth_request_set" 這個指令是在請求通過認證後作變量的設置,這個很不錯的,先壓著。

b、階段設置
ngx_http_auth_request_init(ngx_conf_t *cf)
{
    ngx_http_handler_pt        *h;
    ngx_http_core_main_conf_t  *cmcf;

    cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);

    h = ngx_array_push(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers);
    if (h == NULL) {
        return NGX_ERROR;
    }

   *h = ngx_http_auth_request_handler;

    return NGX_OK;
}

subrequest的源碼有點復雜,將用新篇分析它,這裡不作分析,auth_request是依賴於sub_request的。只需知道
ngx_http_auth_request_handler代碼裡只要返回 return NGX_AGAIN;這函數會一直被調用(一直這個詞有點嚇你,
想象它不會放過fastcgi的handler,一直在fastcgi之前調用)。因為auth_request發生在ACCESS階段, fastcgi在CONTENT階段,ACCESS在CONTENT之前。

3、請求處理 ngx_http_auth_request_handler
static ngx_int_t
ngx_http_auth_request_handler(ngx_http_request_t *r)
{
    ...
 
    ctx = ngx_http_get_module_ctx(r, ngx_http_auth_request_module);
 
 
    if (ctx != NULL) {
        /* 一直拒絕往fastcgi走,直到done */
        if (!ctx->done) {
            return NGX_AGAIN;
        }
 
        /* 調用順序:3  有時閱讀文檔不如閱讀源碼 */
 
        /* 設置auth_request_set的變量 */
        if (ngx_http_auth_request_set_variables(r, arcf, ctx) != NGX_OK) {
            return NGX_ERROR;
        }
 
        /* 如果是403,當作失敗*/
        if (ctx->status == NGX_HTTP_FORBIDDEN) {
            return ctx->status;
        }
 
        /* 這是401,有興趣自己去搜索下,這功能還是很實用的 */
        if (ctx->status == NGX_HTTP_UNAUTHORIZED) {
            sr = ctx->subrequest;
 
            ...
 
            return ctx->status;
        }
 
 
        /* 2xx 當作成功 */
        if (ctx->status >= NGX_HTTP_OK
            && ctx->status < NGX_HTTP_SPECIAL_RESPONSE)
        {
            return NGX_OK;
        }
 
 
        /* 其它當作失敗 */
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }
 
    ...
 
    ps = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t));
 
 
    ps->handler = ngx_http_auth_request_done;
    ps->data = ctx;
 
 
    /* 調用順序:1 這裡發出子請求*/
    ngx_http_subrequest(r, &arcf->uri, NULL, &sr, ps, NGX_HTTP_SUBREQUEST_WAITED);
    ...
 
    ctx->subrequest = sr;
 
    return NGX_AGAIN;
}
 
/* 調用順序:2 設置返回結果 */
static ngx_int_t
ngx_http_auth_request_done(ngx_http_request_t *r, void *data, ngx_int_t rc)
{
    ngx_http_auth_request_ctx_t   *ctx = data;
 
    ctx->done = 1;
    ctx->status = r->headers_out.status;
 
    return rc;
}
到這裡已經沒有任何秘密了。結合返回值和auth_request_set可以做很多更有趣的,比如我寫的那篇nginx動態代理。
甚至你可以拿它寫成更適合你的模塊。期待您的分享。
原文:http://nglua.com/modules/1.html
Copyright © Linux教程網 All Rights Reserved