利用Nginx auth模块快速搭建OAuth2.0 SSO单点登录系统

0

假设我们起了一个服务器在 1234 端口,但是我暴露在公网上,但是又需要被授权的人方便的使用,一般情况下我们会在程序里简单加一个密码验证,或者直接使用 Auth_Basic 设置一个用户名与密码。Nginx Auth_Basic 扫描是恶意爬虫最喜欢干的事,而限制 Auth_Basic 重试次数又需要配置 Fail2ban 之类的日志监控程序,很麻烦。

在应用层设置密码对大多数开发人员来说并没有什么难点,但是有时候我们搭建的系统并不是自己开发的,甚至是已经编译好的庞然大物,就有些困难了。

这里分享一个10分钟快速搭建 OAuth2.0 授权登录系统的方法,本文使用 github 作为示例。

实现的原理是通过nginx的 auth_request 模块检测授权,如果没有授权,返回401错误,nginx将授权请求发送给授权系统,这里使用的是vouch-proxy,如果已经授权,则正常充当反向代理。

多数新版 nginx 的发行版中都已经默认包含了auth_request模块,你可以通过nginx -V命令查看编译参数中是否包含了--with-http_auth_request_module,如果没有可以选择升级 nginx 到最新版或者重新编译 nginx,详情本文不再赘述。

GitHub 配置

首先登录GitHub,建立一个OAuth app,callback URL 填写域名/auth

提交之后你会得到应用的 Client IDClient Secret

Vouch 配置

把这段命令中的client_idclient_secret修改成上一步获取的值。

配置中provider设置的是GitHub,也可以是 Google、AWS Cognito等其他的或自定义库,请多详情可以参考项目主页。

# 建立Vouch配置目录
mkdir -P /var/lib/vouch/config/
mkdir -P /var/lib/vouch/data/

# 建立配置文件
echo '# Vouch config
vouch:
    listen: 0.0.0.0
    port: 9090
    # 授权域名列表
    domains:
    - xiumu.org
    # 允许访问的GitHub ID列表
    whiteList:
    - ixiumu

oauth:
    provider: github
    client_id: 
    client_secret: ' > /var/lib/vouch/config/config.yml

# 拉起vouch服务器
docker run -d -p 9090:9090 --name vouch-proxy -v /var/lib/vouch/config:/config -v /var/lib/vouch/data:/data voucher/vouch-proxy

Nginx 配置

生产环境请配置 SSL 证书开启 HTTPS,粘贴下面的配置到http段,或者在目录/etc/nginx/conf.d新建文件

upstream vouch {
    server 127.0.0.1:9090;
}

server {
    listen 80;
    #listen 443 ssl http2;
    server_name _;

    #ssl_certificate /etc/nginx/____.crt;
    #ssl_certificate_key /etc/nginx/____.key;

    location = /validate {
        # cache validate
        # proxy_cache_valid 200 30s;
        # proxy_cache auth_cache;
        # proxy_cache_methods GET;
        # proxy_cache_key $cookie_vouchcookie;

        # forward the /validate request to Vouch Proxy
        proxy_pass http://vouch;
        # be sure to pass the original host header
        proxy_set_header Host $http_host;

        # Vouch Proxy only acts on the request headers
        proxy_pass_request_body off;
        proxy_set_header Content-Length "";

        # optionally add X-Vouch-User as returned by Vouch Proxy along with the request
        auth_request_set $auth_resp_x_vouch_user $upstream_http_x_vouch_user;

        # optionally add X-Vouch-IdP-Claims-* custom claims you are tracking
        #    auth_request_set $auth_resp_x_vouch_idp_claims_groups $upstream_http_x_vouch_idp_claims_groups;
        #    auth_request_set $auth_resp_x_vouch_idp_claims_given_name $upstream_http_x_vouch_idp_claims_given_name;
        # optinally add X-Vouch-IdP-AccessToken or X-Vouch-IdP-IdToken
        #    auth_request_set $auth_resp_x_vouch_idp_accesstoken $upstream_http_x_vouch_idp_accesstoken;
        #    auth_request_set $auth_resp_x_vouch_idp_idtoken $upstream_http_x_vouch_idp_idtoken;

        # these return values are used by the @error401 call
        auth_request_set $auth_resp_jwt $upstream_http_x_vouch_jwt;
        auth_request_set $auth_resp_err $upstream_http_x_vouch_err;
        auth_request_set $auth_resp_failcount $upstream_http_x_vouch_failcount;
    }

    location /login {
        # forward the /login request to Vouch Proxy
        proxy_pass http://vouch;
        # be sure to pass the original host header
        proxy_set_header Host $http_host;
    }

    location /auth {
        # forward the /auth request to Vouch Proxy
        proxy_pass http://vouch;
        # be sure to pass the original host header
        proxy_set_header Host $http_host;
    }

    # if validate returns `401 not authorized` then forward the request to the error401block
    error_page 401 = @error401;

    location @error401 {
        # redirect to Vouch Proxy for login
        return 302 $scheme://$http_host/login?url=$scheme://$http_host$request_uri&vouch-failcount=$auth_resp_failcount&X-Vouch-Token=$auth_resp_jwt&error=$auth_resp_err;
    }

    # real server
    location / {
        # send all requests to the `/validate` endpoint for authorization
        auth_request /validate;

        proxy_redirect off;
        proxy_http_version 1.1;
        proxy_pass http://127.0.0.1:1234;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Accept-Encoding gzip;
    }
}

重启 Nginx 服务,现在访问网址会跳转到 GitHub 请求授权,之后再访问的时候就会直接连续跳转两次进入应用,几乎感知不到(GitHub抽风的时候要有耐心)。

发表评论

您的邮箱不会公开,当您的评论有新的回复时,会通过您填写的邮箱向您发送评论内容。 必填字段 *

为何看不到我发布的评论?

正在提交, 请稍候...