API接口统一认证

需求

  • 云服务器环境中有多组内网服务器,提供基于RESTFul的微服务;
  • 外网通过Nginx反向代理分发到内网微服务中;
  • 原始设计每个微服务独立验证JWT请求,现在需要在Nginx上进行统一认证,进而提高开发效率;

环境

CentOS 6.10
Nginx 1.16.1

最终方案

  • 系统中不鉴别API参数

配置如下:

upstream auth_server {
    server 192.168.1.250:80;
}

upstream login_server {
    server 192.168.1.10:80;
}

server {
    listen       80;
    server_name  ~^(?.+).jdzchao.com$;
    
    proxy_set_header   Host $host;
    proxy_set_header   Referer $http_referer;
    proxy_set_header   Cookie $http_cookie;
    proxy_set_header   X-Real-IP $remote_addr;
    proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;

    location /
    {
        auth_request /auth;
        error_page 401 = @error401;
        error_page 403 = @error403;
        
        if ($subdomain = 'auth'){
            return 501;
        }
        # return 505;
    }
    
    location /login
    {
        return 403;
    }
    
    location = /auth
    {
        internal;       
        proxy_set_header X-Real-Ip $remote_addr;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header X-Original-HOST $host;
        proxy_set_header X-Original-URI $request_uri;
        proxy_set_header X-Original-METHOD $request_method;
        proxy_pass_request_body off;
        proxy_set_header Content-Length "";
        
        proxy_pass http://auth_server/auth/;
    }
    
    location @error401
    {
        add_header Set-Cookie "NSREDIRECT=$scheme://$http_host$request_uri;Path=/";
        return 302 http://login_server/;
    }
    
    location @error403
    {
        return 405;
    }
}

踩坑方案一: 使用Nginx的Auth_request Module

通过注册auth_server,并开发一个API管理服务。

配置文件:

upstream auth_server {
    server 192.168.1.250:80;
}

upstream login_server {
    server 192.168.1.10:80;
}

server {
    listen       80;
    server_name  ~^(?.+).jdzchao.com$;
    
    proxy_set_header   Host $host;
    proxy_set_header   Referer $http_referer;
    proxy_set_header   Cookie $http_cookie;
    proxy_set_header   X-Real-IP $remote_addr;
    proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;

    location /
    {
        auth_request /auth;
        error_page 401 = @error401;
        error_page 403 = @error403;
        
        if ($subdomain = 'auth'){
            return 501;
        }
        # return 505;
    }
    
    location /login
    {
        return 403;
    }
    
    location = /auth
    {
        internal;   # 内网可访问
        proxy_set_header X-Real-Ip $remote_addr;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header X-Original-HOST $host;
        proxy_set_header X-Original-URI $request_uri;
        proxy_set_header X-Original-METHOD $request_method;
        
        proxy_pass http://auth_server/auth/;
    }
    
    location @error401
    {
        add_header Set-Cookie "NSREDIRECT=$scheme://$http_host$request_uri;Path=/";
        return 302 http://login_server/;
    }
    
    location @error403
    {
        return 405;
    }
}

测试结果:

使用APIPOST进行测试,发送post数据到api.jdzchao.com域名的接口,结果如下:

  • 直接获取的host为 auth_server,不是api.jdzchao.com
  • 只能通过header获取一些转发的信息
  • 请求超时,无响应

更改配置:


# 添加
location = /auth
    {
        internal;   # 内网可访问
        proxy_set_header X-Real-Ip $remote_addr;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header X-Original-HOST $host;
        proxy_set_header X-Original-URI $request_uri;
        proxy_set_header X-Original-METHOD $request_method;
        proxy_pass_request_body off;
        proxy_set_header Content-Length "";
        
        proxy_pass http://auth_server/auth/;
    }

测试结果:

  • 无法获取post和get参数

更改配置:

proxy_pass_request_body on;
proxy_no_cache "1";

测试结果:

仍超时无法获取post和get参数

结论

原因是auth子请求是通过HTTP GET方法发送的,而不是POST.由于GET没有body,body被丢弃
现有模块的唯一解决方法是从请求正文中提取所需信息,并将其放入传递给auth服务的HTTP标头中.

参考文章:

http://nginx.org/en/docs/http/ngx_http_auth_request_module.html
https://www.cnblogs.com/vipzhou/p/8420808.html
https://codeday.me/bug/20190516/1114665.html

你可能感兴趣的:(API接口统一认证)