国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Nginx實現JWT驗證-基于OpenResty實現

xiangchaobin / 3958人閱讀

摘要:用于方便地搭建能夠處理超高并發擴展性極高的動態應用服務和動態網關。

介紹

權限認證是接口開發中不可避免的問題,權限認證包括兩個方面

接口需要知道調用的用戶是誰

接口需要知道該用戶是否有權限調用

第1個問題偏向于架構,第2個問題更偏向于業務,因此考慮在架構層解決第1個問題,以達到以下目的

所有請求被保護的接口保證是合法的(已經認證過的用戶)

接口可以從請求頭中獲取當前用戶信息

每個請求都有uuid用于標識

JWT(JSON Web Token)目前是應用最廣的接口權限方案,具有無狀態,跨系統,多語言多平臺支持等特點,如果能在網關層實現JWT驗證不僅可以避免代碼入侵還能為整個后臺提供統一的解決方案,目前客戶網關使用Nginx,但社區版Nginx中沒有JWT模塊,自己實現不現實,因此選擇OpenResty作為網關層, 據官網介紹,OpenResty? 是一個基于 Nginx 與 Lua 的高性能 Web 平臺,其內部集成了大量精良的 Lua 庫、第三方模塊以及大多數的依賴項。用于方便地搭建能夠處理超高并發、擴展性極高的動態 Web 應用、Web 服務和動態網關。本質上就是一個Nginx+Lua的集成軟件.
整體架構如圖:

實現 環境
[root@docker ~]# cat /etc/redhat-release
CentOS Linux release 7.4.1708 (Core)
[root@docker ~]# more /proc/version
Linux version 3.10.0-693.el7.x86_64 (builder@kbuilder.dev.centos.org) (gcc version 4.8.5 20150623 (Red Hat 4.
8.5-16) (GCC) ) #1 SMP Tue Aug 22 21:09:27 UTC 2017
安裝OpenResty

OpenRestry安裝很簡單,可以在這里找到不同版本操作系統安裝文檔,本次使用的環境是CentOS Linux release 7.4

[root@docker ~]# yum install yum-utils
[root@docker ~]# yum-config-manager --add-repo https://openresty.org/package/centos/openresty.repo
[root@docker ~]# yum install openresty
[root@docker ~]# yum install openresty-resty

系統默認安裝在/usr/local/openresty/目錄下,版本如下

[root@docker openresty]# cd /usr/local/openresty/bin/
[root@docker bin]# ./openresty -v
nginx version: openresty/1.13.6.2

可以將OpenResty目錄加到PATH里,方便使用.

修改nginx.conf文件測試是否安裝成功

tee /usr/local/openresty/nginx/conf/nginx.conf <<-"EOF"
worker_processes  1;
error_log logs/error.log;
events {
    worker_connections 1024;
}
http {
    server {
        listen 8080;
        location / {
            default_type text/html;
            content_by_lua "
                ngx.say("

hello, world

") "; } } } EOF [root@docker conf]# openresty -s reload [root@docker conf]# curl localhost:8080

hello, world

安裝JWT模塊

這里使用JWT官方推薦Lua實現庫,項目地址為https://github.com/SkyLothar/...,有趣的是,這個項目的介紹是這么寫的JWT For The Great Openresty,看來是為OpenResty量身定做.github上有安裝教程,但一方面有些第三方庫的安裝文檔沒有提及,另一方面有些內容沒有用到安裝的時候可以跳過,這里將完整安裝步驟重新整理了下.

在release頁面https://github.com/SkyLothar/...下載項目源碼,截止到目前最新版為v0.1.11

下載hmac源碼,截止到目前項目還未release,只能下載項目里的源文件https://github.com/jkeys089/l...

在服務器創建目錄/usr/local/openresty/nginx/jwt-lua/resty,將第1步壓縮包中目錄lua-resty-jwt-0.1.11/lib/resty/下的所有lua文件和第2步中的hmac.lua文件拷貝到該目錄下,文件列表如下.

[root@docker resty]# pwd
/usr/local/openresty/nginx/jwt-lua/resty
[root@docker resty]# ll
total 60
-rwxr-xr-x. 1 root root 11592 Jul 18 10:40 evp.lua
-rw-r--r--. 1 root root  3796 Jul 18 10:40 hmac.lua
-rwxr-xr-x. 1 root root 27222 Jul 18 10:40 jwt.lua
-rwxr-xr-x. 1 root root 15257 Jul 18 10:40 jwt-validators.lua

修改nginx.conf驗證是否生效

tee /usr/local/openresty/nginx/conf/nginx.conf <<-"EOF"
worker_processes  1;
error_log logs/error.log info;
events {
    worker_connections 1024;
}
http {
    lua_package_path "/usr/local/openresty/nginx/jwt-lua/?.lua;;";
    server {
        listen 8080;
        default_type text/plain;
        location = / {
            content_by_lua "
                local cjson = require "cjson"
                local jwt = require "resty.jwt"

                local jwt_token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9" ..
                    ".eyJmb28iOiJiYXIifQ" ..
                    ".VAoRL1IU0nOguxURF2ZcKR0SGKE1gCbqwyh8u2MLAyY"
                local jwt_obj = jwt:verify("lua-resty-jwt", jwt_token)
                ngx.say(cjson.encode(jwt_obj))
            ";
        }
        location = /sign {
            content_by_lua "
                local cjson = require "cjson"
                local jwt = require "resty.jwt"

                local jwt_token = jwt:sign(
                    "lua-resty-jwt",
                    {
                        header={typ="JWT", alg="HS256"},
                        payload={foo="bar"}
                    }
                )
                ngx.say(jwt_token)
            ";
        }
    }
}
EOF
[root@docker resty]# curl localhost:8080
{"signature":"VAoRL1IU0nOguxURF2ZcKR0SGKE1gCbqwyh8u2MLAyY","reason":"everything is awesome~ :p","valid":true,"raw_header":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9","payload":{"foo":"bar"},"header":{"alg":"HS256","typ":"JWT"},"verified":true,"raw_payload":"eyJmb28iOiJiYXIifQ"}

驗證通過,jwt模塊安裝完畢

自定義驗證邏輯

上面jwt模塊還無法用于生產環境,有幾個問題沒解決

jwt token目前是寫死在配置文件里,生產需要從header Authorization中獲取

驗證失敗目前返回是200生產需要返回401

需要配置反向代理并且將用戶信息放在代理header上

創建文件/usr/local/openresty/nginx/jwt-lua/resty/nginx-jwt.lua
local jwt = require "resty.jwt"
local cjson = require "cjson"
--your secret
local secret = "5pil6aOO5YaN576O5Lmf5q+U5LiN5LiK5bCP6ZuF55qE56yR"

local M = {}

function M.auth(claim_specs)
    -- require Authorization request header
    local auth_header = ngx.var.http_Authorization

    if auth_header == nil then
        ngx.log(ngx.WARN, "No Authorization header")
        ngx.exit(ngx.HTTP_UNAUTHORIZED)
    end

    ngx.log(ngx.INFO, "Authorization: " .. auth_header)

    -- require Bearer token
    local _, _, token = string.find(auth_header, "Bearer%s+(.+)")

    if token == nil then
        ngx.log(ngx.WARN, "Missing token")
        ngx.exit(ngx.HTTP_UNAUTHORIZED)
    end

    ngx.log(ngx.INFO, "Token: " .. token)

    local jwt_obj = jwt:verify(secret, token)
    if jwt_obj.verified == false then
        ngx.log(ngx.WARN, "Invalid token: ".. jwt_obj.reason)
        ngx.exit(ngx.HTTP_UNAUTHORIZED)
    end

    ngx.log(ngx.INFO, "JWT: " .. cjson.encode(jwt_obj))

    -- write the uid variable
    ngx.var.uid = jwt_obj.payload.sub
end

return M
修改配置文件nginx.conf
worker_processes  1;
error_log logs/error.log info;
events {
    worker_connections 1024;
}
http {
    upstream tomcat{
     server localhost:80;
    }
    lua_package_path "/usr/local/openresty/nginx/jwt-lua/?.lua;;";
    server {
        listen 8080;
        set $uid "";
        location / {
            access_by_lua "
            local jwt = require("resty.nginx-jwt")
            jwt.auth()
        ";
            default_type application/json;
            proxy_set_header uid $uid;
            proxy_pass http://tomcat;
        }
    }
}

這里后臺啟動了一臺tomcat并設置監聽端口為80,tomcat上部署了一個示例的war包,代碼邏輯較簡單,就是輸出所有的header,代碼如下:

package asan.demo;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;
import javax.servlet.*;
import javax.servlet.http.*;

public class JWTDemoService extends HttpServlet {
    private static final String CONTENT_TYPE = "text/html; charset=UTF-8";

    public void init(ServletConfig config) throws ServletException {
        super.init(config);
    }

    public void service(HttpServletRequest request,
                        HttpServletResponse response) throws ServletException,
                                                             IOException {
        response.setContentType(CONTENT_TYPE);
        PrintWriter out = response.getWriter();
        Enumeration em=request.getHeaderNames();
        while(em.hasMoreElements()){
            String key=(String)em.nextElement();
            String value=(String)request.getHeaders(key).nextElement();
            out.println(String.format("%s ==> %s", key,value));
        }
        out.close();
    }
}

重啟OpenResty測試,如果沒有指定jwt token信息返回401

[root@docker conf]# curl http://localhost:8080/jwtdemo/service

401 Authorization Required

401 Authorization Required


openresty/1.13.6.2

指定jwt token

[root@docker conf]# curl -i http://localhost:8080/jwtdemo/ -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJ5YXlhIiwiaWF0IjoxNTMxODkyNzE3LCJpc3MiOiJ5YXlhIiwic3ViIjoieWF5YSIsImV4cCI6MTUzMTkyODcxN30.W5UXlwKHSrpUAYbfoF-fTBTS9Enm1wsvCKNQm0yLSfQ"
HTTP/1.1 200
Server: openresty/1.13.6.2
Date: Wed, 18 Jul 2018 05:52:13 GMT
Content-Type: text/html;charset=UTF-8
Content-Length: 298
Connection: keep-alive

uid ==> yaya
host ==> tomcat
connection ==> close
user-agent ==> curl/7.29.0
accept ==> */*
authorization ==> Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJ5YXlhIiwiaWF0IjoxNTMxODkyNzE3LCJpc3MiOiJ5YXlhIiwic3ViIjoieWF5YSIsImV4cCI6MTUzMTkyODcxN30.W5UXlwKHSrpUAYbfoF-fTBTS9Enm1wsvCKNQm0yLSfQ

從結果上看,后臺服務已經獲取到uid這個header
至于請求用到jwt token可以從任意平臺生成只要保證secret一樣即可,根據官網介紹,該庫目前支持到jwt生成算法如圖:

uuid生成

為每個請求生成唯一的uuid碼可以將網關層上的請求和應用層的請求關聯起來,對排查問題,接口統計都非常有用.

創建文件/usr/local/openresty/nginx/jwt-lua/resty/uuid.lua
local M  = {}
local charset = {}  do -- [0-9a-zA-Z]
    for c = 48, 57  do table.insert(charset, string.char(c)) end
    for c = 65, 90  do table.insert(charset, string.char(c)) end
    for c = 97, 122 do table.insert(charset, string.char(c)) end
end
function M.uuid(length)
        local res = ""
        for i = 1, length do
                res = res .. charset[math.random(1, #charset)]
        end
        return res
end
return M
修改配置文件nginx.conf
worker_processes  1;
error_log logs/error.log info;
events {
    worker_connections 1024;
}
http {
    upstream tomcat{
     server localhost:80;
    }
    lua_package_path "/usr/local/openresty/nginx/jwt-lua/?.lua;;";
    server {
        listen 8080;
        set $uid "";
        set $uuid "";
        location / {
            access_by_lua "
            local jwt = require("resty.nginx-jwt")
            jwt.auth()
            local u = require("resty.uuid")
            ngx.var.uuid = u.uuid(64)
        ";
            default_type application/json;
            proxy_set_header uid $uid;
            proxy_set_header uuid $uuid;
            proxy_pass http://tomcat;
        }
    }
}

重啟OpenResty,測試

[root@docker conf]# openresty -s reload
[root@docker conf]# curl -i http://localhost:8080/jwtdemo/ -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJ5YXlhIiwiaWF0IjoxNTMxODk0MDA3LCJpc3MiOiJ5YXlhIiwic3ViIjoieWF5YSIsImV4cCI6MTUzMTkzMDAwN30.vQvpQpIHCmK5QBgIoRR8jhIGeYlHOMYySIr4gHvoZFE"
HTTP/1.1 200
Server: openresty/1.13.6.2
Date: Wed, 18 Jul 2018 08:05:45 GMT
Content-Type: text/html;charset=UTF-8
Content-Length: 372
Connection: keep-alive

uid ==> yaya
uuid ==> nhak5eLjQZ73yhAyHLTgZnSBeDa8pa1p3pcpBFvJ4Mv1fkY782UgVr8Islheq03l
host ==> tomcat
connection ==> close
user-agent ==> curl/7.29.0
accept ==> */*
authorization ==> Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJ5YXlhIiwiaWF0IjoxNTMxODk0MDA3LCJpc3MiOiJ5YXlhIiwic3ViIjoieWF5YSIsImV4cCI6MTUzMTkzMDAwN30.vQvpQpIHCmK5QBgIoRR8jhIGeYlHOMYySIr4gHvoZFE

可以看到,多了一個uuid的請求頭

jwt token生成java示例

這里提供一個生成jwt token的java示例

package com.yaya;

import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import javax.crypto.spec.SecretKeySpec;
import java.security.Key;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @Description:
 * @author: jianfeng.zheng
 * @since: 2018/7/5 下午9:56
 * @history: 1.2018/7/5 created by jianfeng.zheng
 */
public class JWTDemo {
    
    public static final String SECRET="5pil6aOO5YaN576O5Lmf5q+U5LiN5LiK5bCP6ZuF55qE56yR";
    
    public static String createJWT(String uid, long ttlMillis) throws Exception {
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
        Key signingKey = new SecretKeySpec(SECRET.getBytes(), signatureAlgorithm.getJcaName());

        Map header=new HashMap();
        header.put("typ","JWT");
        header.put("alg","HS256");
        JwtBuilder builder = Jwts.builder().setId(uid)
                .setIssuedAt(now)
                .setIssuer(uid)
                .setSubject(uid)
                .setHeader(header)
                .signWith(signatureAlgorithm, signingKey);
        if (ttlMillis >= 0) {
            long expMillis = nowMillis + ttlMillis;
            Date exp = new Date(expMillis);
            builder.setExpiration(exp);
        }
        return builder.compact();
    }

    public static void main(String[]cmd) throws Exception {
        String s=createJWT("yaya",36000000);
        System.out.println("Bearer "+s);
    }

}

pom.xml



    4.0.0

    com.yaya
    jwtdemo
    1.0-SNAPSHOT
    
        
            io.jsonwebtoken
            jjwt
            0.6.0
        
    
寫在最后

這里只是解決了文章開頭提到的第一個問題,接口需要知道是誰調用了接口,第二個問題,用戶能不能調接口目前考慮用aop在應用層實現,后續也會繼續更新.

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/40008.html

相關文章

  • 日志平臺(網關層) - 基于Openresty+ELKF+Kafka

    摘要:現在用方式調用接口,中使用方式輸入內容日志平臺網關層基于。日志平臺網關層基于到此為止,提取經過網關的接口信息,并將其寫入日志文件就完成了,所有的接口日志都寫入了文件中。 背景介紹 1、問題現狀與嘗試 沒有做日志記錄的線上系統,絕對是給系統運維人員留下的坑。尤其是前后端分離的項目,后端的接口日志可以解決對接、測試和運維時的很多問題。之前項目上發布的接口都是通過Oracle Service...

    xumenger 評論0 收藏0
  • Mac下使用ABTestingGateway快速搭建灰度網關

    摘要:下使用快速搭建灰度網關簡介是新浪開源的一個可以動態設置分流策略的灰度發布系統,工作在層,基于和開發,使用作為分流策略數據庫,可以實現動態調度功能。目前在京東如實時價格秒殺動態服務單品頁列表頁等都在使用架構,其他公司如淘寶去哪兒網等。 Mac下使用ABTestingGateway快速搭建灰度網關 ABTestingGateway簡介 ABTestingGateway 是新浪開源的一個可以...

    2bdenny 評論0 收藏0
  • k8s與監控--引入traefik做后端服務的反代

    摘要:我們整個監控的部分,沒有采用社區流行的,而是自己實現了一套。但是對于前端來說,只暴露一個入口,引入一個反代即可。簡介是一個為了讓部署微服務更加便捷而誕生的現代反向代理負載均衡工具。配置熱更新,支持多種后端。將請求轉發到統一認證服務。 前言 對于監控這塊,我們基于prometheus實現,當然做了大量的優化,包括前面所講到的配置接口化。我們整個監控的UI部分,沒有采用社區流行的grafa...

    AZmake 評論0 收藏0
  • k8s與監控--引入traefik做后端服務的反代

    摘要:我們整個監控的部分,沒有采用社區流行的,而是自己實現了一套。但是對于前端來說,只暴露一個入口,引入一個反代即可。簡介是一個為了讓部署微服務更加便捷而誕生的現代反向代理負載均衡工具。配置熱更新,支持多種后端。將請求轉發到統一認證服務。 前言 對于監控這塊,我們基于prometheus實現,當然做了大量的優化,包括前面所講到的配置接口化。我們整個監控的UI部分,沒有采用社區流行的grafa...

    kgbook 評論0 收藏0

發表評論

0條評論

xiangchaobin

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<